[COMMAND MENU ITEMS] Remove deprecated code (#19199)
This PR is the first one of a cleanup after upgrading command menu items to V2.
This commit is contained in:
+231
@@ -0,0 +1,231 @@
|
||||
import { type HeadlessEngineCommandContextApi } from '@/command-menu-item/engine-command/types/HeadlessCommandContextApi';
|
||||
import { useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation } from '@/command-menu-item/engine-command/hooks/useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
||||
import { type ReactNode } from 'react';
|
||||
import {
|
||||
CommandMenuItemAvailabilityType,
|
||||
EngineComponentKey,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const mockFindOneWorkflowVersion = jest.fn();
|
||||
const mockEnqueueWarningSnackBar = jest.fn();
|
||||
const mockBuildTriggerWorkflowVersionPayloads = jest.fn();
|
||||
|
||||
jest.mock('@/object-record/hooks/useLazyFindOneRecord', () => ({
|
||||
useLazyFindOneRecord: () => ({
|
||||
findOneRecord: mockFindOneWorkflowVersion,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@/ui/feedback/snack-bar-manager/hooks/useSnackBar', () => ({
|
||||
useSnackBar: () => ({
|
||||
enqueueWarningSnackBar: mockEnqueueWarningSnackBar,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
'@/command-menu-item/engine-command/utils/buildTriggerWorkflowVersionPayloads',
|
||||
() => ({
|
||||
buildTriggerWorkflowVersionPayloads: (...args: unknown[]) =>
|
||||
mockBuildTriggerWorkflowVersionPayloads(...args),
|
||||
}),
|
||||
);
|
||||
|
||||
const getWrapper =
|
||||
(store = createStore()) =>
|
||||
({ children }: { children: ReactNode }) => (
|
||||
<JotaiProvider store={store}>{children}</JotaiProvider>
|
||||
);
|
||||
|
||||
const buildBaseContextApi = (
|
||||
overrides: Partial<HeadlessEngineCommandContextApi> = {},
|
||||
): HeadlessEngineCommandContextApi => ({
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
objectMetadataItem: null,
|
||||
currentViewId: null,
|
||||
recordIndexId: null,
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds: [] },
|
||||
selectedRecords: [],
|
||||
graphqlFilter: null,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return enriched context API with workflow info and payloads', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const workflowVersionRecord = {
|
||||
id: 'wf-version-1',
|
||||
workflowId: 'workflow-1',
|
||||
trigger: { type: 'MANUAL' },
|
||||
__typename: 'WorkflowVersion' as const,
|
||||
};
|
||||
|
||||
mockFindOneWorkflowVersion.mockImplementation(
|
||||
async ({ onCompleted }: { onCompleted: (data: unknown) => void }) => {
|
||||
onCompleted(workflowVersionRecord);
|
||||
},
|
||||
);
|
||||
|
||||
const expectedPayloads = [{ recordId: 'rec-1' }];
|
||||
mockBuildTriggerWorkflowVersionPayloads.mockReturnValue(expectedPayloads);
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
const headlessEngineCommandContextApi = buildBaseContextApi();
|
||||
|
||||
let enrichedResult: unknown;
|
||||
|
||||
await act(async () => {
|
||||
enrichedResult =
|
||||
await result.current.enrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(
|
||||
{
|
||||
headlessEngineCommandContextApi,
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(enrichedResult).toEqual({
|
||||
...headlessEngineCommandContextApi,
|
||||
workflowId: 'workflow-1',
|
||||
workflowVersionId: 'wf-version-1',
|
||||
payloads: expectedPayloads,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined when workflow version is not found', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
mockFindOneWorkflowVersion.mockImplementation(async () => {});
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
let enrichedResult: unknown;
|
||||
|
||||
await act(async () => {
|
||||
enrichedResult =
|
||||
await result.current.enrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(
|
||||
{
|
||||
headlessEngineCommandContextApi: buildBaseContextApi(),
|
||||
workflowVersionId: 'nonexistent',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(enrichedResult).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined for RECORD_SELECTION type when payloads are empty', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const workflowVersionRecord = {
|
||||
id: 'wf-version-1',
|
||||
workflowId: 'workflow-1',
|
||||
trigger: { type: 'MANUAL' },
|
||||
__typename: 'WorkflowVersion' as const,
|
||||
};
|
||||
|
||||
mockFindOneWorkflowVersion.mockImplementation(
|
||||
async ({ onCompleted }: { onCompleted: (data: unknown) => void }) => {
|
||||
onCompleted(workflowVersionRecord);
|
||||
},
|
||||
);
|
||||
|
||||
mockBuildTriggerWorkflowVersionPayloads.mockReturnValue([]);
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
let enrichedResult: unknown;
|
||||
|
||||
await act(async () => {
|
||||
enrichedResult =
|
||||
await result.current.enrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(
|
||||
{
|
||||
headlessEngineCommandContextApi: buildBaseContextApi(),
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(enrichedResult).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should show warning snackbar when selected records exceed QUERY_MAX_RECORDS', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const workflowVersionRecord = {
|
||||
id: 'wf-version-1',
|
||||
workflowId: 'workflow-1',
|
||||
trigger: { type: 'MANUAL' },
|
||||
__typename: 'WorkflowVersion' as const,
|
||||
};
|
||||
|
||||
mockFindOneWorkflowVersion.mockImplementation(
|
||||
async ({ onCompleted }: { onCompleted: (data: unknown) => void }) => {
|
||||
onCompleted(workflowVersionRecord);
|
||||
},
|
||||
);
|
||||
|
||||
mockBuildTriggerWorkflowVersionPayloads.mockReturnValue([
|
||||
{ recordId: 'rec-1' },
|
||||
]);
|
||||
|
||||
const selectedRecordIds = Array.from({ length: 201 }, (_, index) =>
|
||||
String(index),
|
||||
);
|
||||
|
||||
const headlessEngineCommandContextApi = buildBaseContextApi({
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds },
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.enrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation(
|
||||
{
|
||||
headlessEngineCommandContextApi,
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(mockEnqueueWarningSnackBar).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
options: {
|
||||
dedupeKey: 'workflow-manual-trigger-selection-limit',
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
import { headlessCommandContextApisState } from '@/command-menu-item/engine-command/states/headlessCommandContextApisState';
|
||||
import { type HeadlessEngineCommandContextApi } from '@/command-menu-item/engine-command/types/HeadlessCommandContextApi';
|
||||
import { useHeadlessCommandContextApi } from '@/command-menu-item/engine-command/hooks/useHeadlessCommandContextApi';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
||||
import { type ReactNode } from 'react';
|
||||
import { EngineComponentKey } from '~/generated-metadata/graphql';
|
||||
|
||||
const TEST_ENGINE_COMMAND_ID = 'test-engine-cmd-1';
|
||||
|
||||
jest.mock(
|
||||
'@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow',
|
||||
() => ({
|
||||
useAvailableComponentInstanceIdOrThrow: () => TEST_ENGINE_COMMAND_ID,
|
||||
}),
|
||||
);
|
||||
|
||||
const getWrapper =
|
||||
(store = createStore()) =>
|
||||
({ children }: { children: ReactNode }) => (
|
||||
<JotaiProvider store={store}>{children}</JotaiProvider>
|
||||
);
|
||||
|
||||
const buildHeadlessContextApi = (
|
||||
overrides: Partial<HeadlessEngineCommandContextApi> = {},
|
||||
): HeadlessEngineCommandContextApi => ({
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
objectMetadataItem: null,
|
||||
currentViewId: null,
|
||||
recordIndexId: null,
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds: [] },
|
||||
selectedRecords: [],
|
||||
graphqlFilter: null,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('useHeadlessCommandContextApi', () => {
|
||||
it('should return the HeadlessCommandContextApi for the current instance id', () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const contextApi = buildHeadlessContextApi();
|
||||
store.set(
|
||||
headlessCommandContextApisState.atom,
|
||||
new Map([[TEST_ENGINE_COMMAND_ID, contextApi]]),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => useHeadlessCommandContextApi(), {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
expect(result.current).toEqual(contextApi);
|
||||
});
|
||||
|
||||
it('should throw when no entry exists for the instance id', () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
store.set(headlessCommandContextApisState.atom, new Map());
|
||||
|
||||
expect(() =>
|
||||
renderHook(() => useHeadlessCommandContextApi(), { wrapper }),
|
||||
).toThrow(
|
||||
'Headless command context API not found. Make sure the command was mounted via the command mount flow.',
|
||||
);
|
||||
});
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { useIsHeadlessEngineCommandEffectInitialized } from '@/command-menu-item/engine-command/hooks/useIsHeadlessEngineCommandEffectInitialized';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
describe('useIsHeadlessEngineCommandEffectInitialized', () => {
|
||||
it('should return isInitializedRef as false initially', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useIsHeadlessEngineCommandEffectInitialized(),
|
||||
);
|
||||
|
||||
expect(result.current.isInitializedRef.current).toBe(false);
|
||||
});
|
||||
|
||||
it('should update isInitializedRef to true after calling setIsInitialized(true)', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useIsHeadlessEngineCommandEffectInitialized(),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.setIsInitialized(true);
|
||||
});
|
||||
|
||||
expect(result.current.isInitializedRef.current).toBe(true);
|
||||
});
|
||||
|
||||
it('should toggle back to false after calling setIsInitialized(false)', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useIsHeadlessEngineCommandEffectInitialized(),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.setIsInitialized(true);
|
||||
});
|
||||
|
||||
expect(result.current.isInitializedRef.current).toBe(true);
|
||||
|
||||
act(() => {
|
||||
result.current.setIsInitialized(false);
|
||||
});
|
||||
|
||||
expect(result.current.isInitializedRef.current).toBe(false);
|
||||
});
|
||||
});
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
import { headlessCommandContextApisState } from '@/command-menu-item/engine-command/states/headlessCommandContextApisState';
|
||||
import { type HeadlessEngineCommandContextApi } from '@/command-menu-item/engine-command/types/HeadlessCommandContextApi';
|
||||
import { useMountCommand } from '@/command-menu-item/engine-command/hooks/useMountCommand';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
||||
import { type ReactNode } from 'react';
|
||||
import {
|
||||
CommandMenuItemAvailabilityType,
|
||||
EngineComponentKey,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const mockEnrichFn = jest.fn();
|
||||
|
||||
jest.mock(
|
||||
'@/command-menu-item/engine-command/hooks/useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation',
|
||||
() => ({
|
||||
useEnrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation:
|
||||
() => ({
|
||||
enrichHeadlessCommandContextApiWithWorkflowVersionTriggerInformation:
|
||||
mockEnrichFn,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
const baseContextApi: HeadlessEngineCommandContextApi = {
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
objectMetadataItem: null,
|
||||
currentViewId: null,
|
||||
recordIndexId: null,
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds: [] },
|
||||
selectedRecords: [],
|
||||
graphqlFilter: null,
|
||||
};
|
||||
|
||||
jest.mock(
|
||||
'@/command-menu-item/engine-command/utils/buildHeadlessCommandContextApi',
|
||||
() => ({
|
||||
buildHeadlessCommandContextApi: () => baseContextApi,
|
||||
}),
|
||||
);
|
||||
|
||||
const getWrapper =
|
||||
(store = createStore()) =>
|
||||
({ children }: { children: ReactNode }) => (
|
||||
<JotaiProvider store={store}>{children}</JotaiProvider>
|
||||
);
|
||||
|
||||
describe('useMountCommand', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should mount with frontComponentId when provided', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const { result } = renderHook(() => useMountCommand(), { wrapper });
|
||||
|
||||
await act(async () => {
|
||||
await result.current({
|
||||
engineCommandId: 'cmd-1',
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
frontComponentId: 'front-comp-1',
|
||||
});
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.get('cmd-1')).toEqual({
|
||||
...baseContextApi,
|
||||
frontComponentId: 'front-comp-1',
|
||||
});
|
||||
expect(mockEnrichFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should mount with workflow enrichment when workflowVersionId and availabilityType are provided', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const enrichedState = {
|
||||
...baseContextApi,
|
||||
workflowId: 'workflow-1',
|
||||
workflowVersionId: 'wf-version-1',
|
||||
payloads: [{ recordId: 'rec-1' }],
|
||||
};
|
||||
mockEnrichFn.mockResolvedValue(enrichedState);
|
||||
|
||||
const { result } = renderHook(() => useMountCommand(), { wrapper });
|
||||
|
||||
await act(async () => {
|
||||
await result.current({
|
||||
engineCommandId: 'cmd-1',
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
});
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.get('cmd-1')).toEqual(enrichedState);
|
||||
expect(mockEnrichFn).toHaveBeenCalledWith({
|
||||
headlessEngineCommandContextApi: baseContextApi,
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should mount with base headless context API when neither frontComponentId nor workflow params are provided', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const { result } = renderHook(() => useMountCommand(), { wrapper });
|
||||
|
||||
await act(async () => {
|
||||
await result.current({
|
||||
engineCommandId: 'cmd-1',
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
});
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.get('cmd-1')).toEqual(baseContextApi);
|
||||
expect(mockEnrichFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not set state when workflow enrichment returns undefined', async () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
mockEnrichFn.mockResolvedValue(undefined);
|
||||
|
||||
const { result } = renderHook(() => useMountCommand(), { wrapper });
|
||||
|
||||
await act(async () => {
|
||||
await result.current({
|
||||
engineCommandId: 'cmd-1',
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
workflowVersionId: 'wf-version-1',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
});
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.has('cmd-1')).toBe(false);
|
||||
});
|
||||
});
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
import { headlessCommandContextApisState } from '@/command-menu-item/engine-command/states/headlessCommandContextApisState';
|
||||
import { type HeadlessEngineCommandContextApi } from '@/command-menu-item/engine-command/types/HeadlessCommandContextApi';
|
||||
import { useUnmountCommand } from '@/command-menu-item/engine-command/hooks/useUnmountEngineCommand';
|
||||
import { commandMenuItemProgressFamilyState } from '@/command-menu-item/states/commandMenuItemProgressFamilyState';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
||||
import { type ReactNode } from 'react';
|
||||
import { EngineComponentKey } from '~/generated-metadata/graphql';
|
||||
|
||||
const getWrapper =
|
||||
(store = createStore()) =>
|
||||
({ children }: { children: ReactNode }) => (
|
||||
<JotaiProvider store={store}>{children}</JotaiProvider>
|
||||
);
|
||||
|
||||
const buildHeadlessContextApi = (
|
||||
overrides: Partial<HeadlessEngineCommandContextApi> = {},
|
||||
): HeadlessEngineCommandContextApi => ({
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
objectMetadataItem: null,
|
||||
currentViewId: null,
|
||||
recordIndexId: null,
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds: [] },
|
||||
selectedRecords: [],
|
||||
graphqlFilter: null,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('useUnmountCommand', () => {
|
||||
it('should remove entry from headlessCommandContextApisState map', () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const contextApi = buildHeadlessContextApi();
|
||||
store.set(
|
||||
headlessCommandContextApisState.atom,
|
||||
new Map([['cmd-1', contextApi]]),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => useUnmountCommand(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current('cmd-1');
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.has('cmd-1')).toBe(false);
|
||||
expect(map.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should reset commandMenuItemProgressFamilyState for the given id to undefined', () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
store.set(commandMenuItemProgressFamilyState.atomFamily('cmd-1'), 50);
|
||||
|
||||
const { result } = renderHook(() => useUnmountCommand(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current('cmd-1');
|
||||
});
|
||||
|
||||
const progress = store.get(
|
||||
commandMenuItemProgressFamilyState.atomFamily('cmd-1'),
|
||||
);
|
||||
|
||||
expect(progress).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not affect other entries in the map', () => {
|
||||
const store = createStore();
|
||||
const wrapper = getWrapper(store);
|
||||
|
||||
const contextApi1 = buildHeadlessContextApi({
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
});
|
||||
const contextApi2 = buildHeadlessContextApi({
|
||||
contextStoreInstanceId: 'ctx-2',
|
||||
});
|
||||
|
||||
store.set(
|
||||
headlessCommandContextApisState.atom,
|
||||
new Map([
|
||||
['cmd-1', contextApi1],
|
||||
['cmd-2', contextApi2],
|
||||
]),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => useUnmountCommand(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current('cmd-1');
|
||||
});
|
||||
|
||||
const map = store.get(headlessCommandContextApisState.atom);
|
||||
|
||||
expect(map.has('cmd-1')).toBe(false);
|
||||
expect(map.has('cmd-2')).toBe(true);
|
||||
expect(map.get('cmd-2')).toEqual(contextApi2);
|
||||
});
|
||||
});
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
import { HeadlessEngineCommandWrapperEffect } from '@/command-menu-item/engine-command/components/HeadlessEngineCommandWrapperEffect';
|
||||
import { useHeadlessCommandContextApi } from '@/command-menu-item/engine-command/hooks/useHeadlessCommandContextApi';
|
||||
import { useSelectedRecordIdOrThrow } from '@/command-menu-item/record/single-record/hooks/useSelectedRecordIdOrThrow';
|
||||
import { useRecordPageLayoutIdFromRecordStoreOrThrow } from '@/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow';
|
||||
import { useResetDraftPageLayoutToPersistedPageLayout } from '@/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout';
|
||||
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
|
||||
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { PageLayoutType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const CancelRecordPageLayoutSingleRecordCommand = () => {
|
||||
const { objectMetadataItem } = useHeadlessCommandContextApi();
|
||||
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
throw new Error(
|
||||
'Object metadata item is required to cancel record page layout',
|
||||
);
|
||||
}
|
||||
|
||||
const recordId = useSelectedRecordIdOrThrow();
|
||||
|
||||
const { pageLayoutId } = useRecordPageLayoutIdFromRecordStoreOrThrow({
|
||||
targetObjectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const tabListInstanceId = getTabListInstanceIdFromPageLayoutAndRecord({
|
||||
pageLayoutId,
|
||||
layoutType: PageLayoutType.RECORD_PAGE,
|
||||
targetRecordIdentifier: {
|
||||
id: recordId,
|
||||
targetObjectNameSingular: objectMetadataItem.nameSingular,
|
||||
},
|
||||
});
|
||||
|
||||
const { closeSidePanelMenu } = useSidePanelMenu();
|
||||
|
||||
const { setIsPageLayoutInEditMode } =
|
||||
useSetIsPageLayoutInEditMode(pageLayoutId);
|
||||
|
||||
const { resetDraftPageLayoutToPersistedPageLayout } =
|
||||
useResetDraftPageLayoutToPersistedPageLayout({
|
||||
pageLayoutId,
|
||||
tabListInstanceId,
|
||||
});
|
||||
|
||||
const handleExecute = () => {
|
||||
closeSidePanelMenu();
|
||||
|
||||
resetDraftPageLayoutToPersistedPageLayout();
|
||||
setIsPageLayoutInEditMode(false);
|
||||
};
|
||||
|
||||
return <HeadlessEngineCommandWrapperEffect execute={handleExecute} />;
|
||||
};
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
import { HeadlessEngineCommandWrapperEffect } from '@/command-menu-item/engine-command/components/HeadlessEngineCommandWrapperEffect';
|
||||
import { useHeadlessCommandContextApi } from '@/command-menu-item/engine-command/hooks/useHeadlessCommandContextApi';
|
||||
import { useRecordPageLayoutIdFromRecordStoreOrThrow } from '@/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow';
|
||||
import { useSavePageLayout } from '@/page-layout/hooks/useSavePageLayout';
|
||||
import { useSavePageLayoutWidgetsData } from '@/page-layout/hooks/useSavePageLayoutWidgetsData';
|
||||
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const SaveRecordPageLayoutSingleRecordCommand = () => {
|
||||
const { objectMetadataItem } = useHeadlessCommandContextApi();
|
||||
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
throw new Error(
|
||||
'Object metadata item is required to save record page layout',
|
||||
);
|
||||
}
|
||||
|
||||
const { pageLayoutId } = useRecordPageLayoutIdFromRecordStoreOrThrow({
|
||||
targetObjectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const { savePageLayout } = useSavePageLayout(pageLayoutId);
|
||||
|
||||
const { savePageLayoutWidgetsData } = useSavePageLayoutWidgetsData();
|
||||
|
||||
const { setIsPageLayoutInEditMode } =
|
||||
useSetIsPageLayoutInEditMode(pageLayoutId);
|
||||
|
||||
const { closeSidePanelMenu } = useSidePanelMenu();
|
||||
|
||||
const handleExecute = async () => {
|
||||
const result = await savePageLayout();
|
||||
|
||||
if (result.status === 'successful') {
|
||||
await savePageLayoutWidgetsData(pageLayoutId);
|
||||
|
||||
closeSidePanelMenu();
|
||||
setIsPageLayoutInEditMode(false);
|
||||
}
|
||||
};
|
||||
|
||||
return <HeadlessEngineCommandWrapperEffect execute={handleExecute} />;
|
||||
};
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import { type HeadlessCommandContextApi } from '@/command-menu-item/engine-command/types/HeadlessCommandContextApi';
|
||||
import { isHeadlessTriggerWorkflowVersionCommandContextApi } from '@/command-menu-item/engine-command/utils/isHeadlessTriggerWorkflowVersionCommandContextApi';
|
||||
import { EngineComponentKey } from '~/generated-metadata/graphql';
|
||||
|
||||
const baseContextApi: HeadlessCommandContextApi = {
|
||||
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
||||
contextStoreInstanceId: 'ctx-1',
|
||||
objectMetadataItem: null,
|
||||
currentViewId: null,
|
||||
recordIndexId: null,
|
||||
targetedRecordsRule: { mode: 'selection', selectedRecordIds: [] },
|
||||
selectedRecords: [],
|
||||
graphqlFilter: null,
|
||||
};
|
||||
|
||||
describe('isHeadlessTriggerWorkflowVersionCommandContextApi', () => {
|
||||
it('should return true when state has workflowId', () => {
|
||||
const triggerWorkflowContext: HeadlessCommandContextApi = {
|
||||
...baseContextApi,
|
||||
workflowId: 'wf-1',
|
||||
workflowVersionId: 'wfv-1',
|
||||
payloads: [],
|
||||
};
|
||||
|
||||
expect(
|
||||
isHeadlessTriggerWorkflowVersionCommandContextApi(triggerWorkflowContext),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for plain HeadlessEngineCommandContextApi', () => {
|
||||
expect(
|
||||
isHeadlessTriggerWorkflowVersionCommandContextApi(baseContextApi),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for HeadlessFrontComponentCommandContextApi', () => {
|
||||
const frontComponentContext: HeadlessCommandContextApi = {
|
||||
...baseContextApi,
|
||||
frontComponentId: 'fc-1',
|
||||
};
|
||||
|
||||
expect(
|
||||
isHeadlessTriggerWorkflowVersionCommandContextApi(frontComponentContext),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user