584 Refactor Tabs (#11008)
Closes https://github.com/twentyhq/core-team-issues/issues/584 This PR: - Migrates the component state `activeTabIdComponentState` from the deprecated V1 version to V2. - Allows the active tab state to be preserved during navigation inside the side panel and reset when the side panel is closed. - Allows the active tab state to be preserved when we open a record in full page from the side panel https://github.com/user-attachments/assets/f2329d7a-ea15-4bd8-81dc-e98ce11edbd0 https://github.com/user-attachments/assets/474bffd5-29e0-40ba-97f4-fa5e9be34dc2
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { useTabListStates } from '@/ui/layout/tab/hooks/internal/useTabListStates';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
||||
@ -24,27 +24,29 @@ export const WorkflowRunDiagramCanvasEffect = () => {
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
|
||||
const { activeTabIdState: workflowRunRightDrawerListActiveTabIdState } =
|
||||
useTabListStates({
|
||||
tabListScopeId: WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID,
|
||||
});
|
||||
|
||||
const goBackToFirstWorkflowRunRightDrawerTabIfNeeded = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
const activeWorkflowRunRightDrawerTab = getSnapshotValue(
|
||||
snapshot,
|
||||
workflowRunRightDrawerListActiveTabIdState,
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID,
|
||||
}),
|
||||
) as WorkflowRunTabId | null;
|
||||
|
||||
if (
|
||||
activeWorkflowRunRightDrawerTab === 'input' ||
|
||||
activeWorkflowRunRightDrawerTab === 'output'
|
||||
) {
|
||||
set(workflowRunRightDrawerListActiveTabIdState, 'node');
|
||||
set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID,
|
||||
}),
|
||||
'node',
|
||||
);
|
||||
}
|
||||
},
|
||||
[workflowRunRightDrawerListActiveTabIdState],
|
||||
[],
|
||||
);
|
||||
|
||||
const handleSelectionChange = useCallback(
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { RightDrawerWorkflowEditStepContent } from '@/workflow/workflow-steps/components/RightDrawerWorkflowEditStepContent';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const RightDrawerWorkflowEditStep = () => {
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
||||
|
||||
if (!isDefined(workflow)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<WorkflowStepContextProvider
|
||||
value={{ workflowVersionId: workflow.currentVersion.id }}
|
||||
>
|
||||
<RightDrawerWorkflowEditStepContent workflow={workflow} />
|
||||
</WorkflowStepContextProvider>
|
||||
);
|
||||
};
|
||||
@ -1,30 +0,0 @@
|
||||
import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
|
||||
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
||||
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
||||
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
||||
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
||||
|
||||
export const RightDrawerWorkflowEditStepContent = ({
|
||||
workflow,
|
||||
}: {
|
||||
workflow: WorkflowWithCurrentVersion;
|
||||
}) => {
|
||||
const flow = useFlowOrThrow();
|
||||
const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
|
||||
|
||||
const { updateTrigger } = useUpdateWorkflowVersionTrigger({ workflow });
|
||||
const { updateStep } = useUpdateStep({
|
||||
workflow,
|
||||
});
|
||||
|
||||
return (
|
||||
<WorkflowStepDetail
|
||||
stepId={workflowSelectedNode}
|
||||
trigger={flow.trigger}
|
||||
steps={flow.steps}
|
||||
onActionUpdate={updateStep}
|
||||
onTriggerUpdate={updateTrigger}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -1,102 +0,0 @@
|
||||
import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
|
||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
||||
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
||||
import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail';
|
||||
import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail';
|
||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
||||
import { WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/constants/WorkflowRunStepSidePanelTabListComponentId';
|
||||
import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus';
|
||||
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
|
||||
import styled from '@emotion/styled';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui';
|
||||
|
||||
const StyledTabList = styled(TabList)`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type TabId = 'node' | 'input' | 'output';
|
||||
|
||||
export const RightDrawerWorkflowRunViewStep = () => {
|
||||
const flow = useFlowOrThrow();
|
||||
const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
|
||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||
|
||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||
|
||||
const { activeTabId } = useTabList<TabId>(
|
||||
WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID,
|
||||
);
|
||||
|
||||
const stepExecutionStatus = isDefined(workflowRun)
|
||||
? getWorkflowRunStepExecutionStatus({
|
||||
workflowRunOutput: workflowRun.output,
|
||||
stepId: workflowSelectedNode,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const areInputAndOutputTabsDisabled =
|
||||
workflowSelectedNode === TRIGGER_STEP_ID ||
|
||||
stepExecutionStatus === 'running' ||
|
||||
stepExecutionStatus === 'not-executed';
|
||||
|
||||
const tabs: SingleTabProps<TabId>[] = [
|
||||
{ id: 'node', title: 'Node', Icon: IconStepInto },
|
||||
{
|
||||
id: 'input',
|
||||
title: 'Input',
|
||||
Icon: IconLogin2,
|
||||
disabled: areInputAndOutputTabsDisabled,
|
||||
},
|
||||
{
|
||||
id: 'output',
|
||||
title: 'Output',
|
||||
Icon: IconLogout,
|
||||
disabled: areInputAndOutputTabsDisabled,
|
||||
},
|
||||
];
|
||||
|
||||
if (!isDefined(workflowRun)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<WorkflowStepContextProvider
|
||||
value={{ workflowVersionId: flow.workflowVersionId }}
|
||||
>
|
||||
<StyledTabList
|
||||
tabListInstanceId={WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID}
|
||||
tabs={tabs}
|
||||
behaveAsLinks={false}
|
||||
/>
|
||||
|
||||
{activeTabId === 'node' ? (
|
||||
<WorkflowStepDetail
|
||||
readonly
|
||||
stepId={workflowSelectedNode}
|
||||
trigger={flow.trigger}
|
||||
steps={flow.steps}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{activeTabId === 'input' ? (
|
||||
<WorkflowRunStepInputDetail
|
||||
key={workflowSelectedNode}
|
||||
stepId={workflowSelectedNode}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{activeTabId === 'output' ? (
|
||||
<WorkflowRunStepOutputDetail
|
||||
key={workflowSelectedNode}
|
||||
stepId={workflowSelectedNode}
|
||||
/>
|
||||
) : null}
|
||||
</WorkflowStepContextProvider>
|
||||
);
|
||||
};
|
||||
@ -1,213 +0,0 @@
|
||||
import { flowState } from '@/workflow/states/flowState';
|
||||
import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
|
||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
||||
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
|
||||
import styled from '@emotion/styled';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
||||
import { HttpResponse, graphql } from 'msw';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { oneFailedWorkflowRunQueryResult } from '~/testing/mock-data/workflow-run';
|
||||
import { RightDrawerWorkflowRunViewStep } from '../RightDrawerWorkflowRunViewStep';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 500px;
|
||||
`;
|
||||
|
||||
const meta: Meta<typeof RightDrawerWorkflowRunViewStep> = {
|
||||
title: 'Modules/Workflow/RightDrawerWorkflowRunViewStep',
|
||||
component: RightDrawerWorkflowRunViewStep,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<StyledWrapper>
|
||||
<Story />
|
||||
</StyledWrapper>
|
||||
),
|
||||
I18nFrontDecorator,
|
||||
ComponentDecorator,
|
||||
(Story) => {
|
||||
const setFlow = useSetRecoilState(flowState);
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
const setWorkflowRunId = useSetRecoilState(workflowRunIdState);
|
||||
|
||||
setFlow({
|
||||
workflowVersionId:
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.workflowVersionId,
|
||||
trigger:
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.output.flow.trigger,
|
||||
steps: oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps,
|
||||
});
|
||||
setWorkflowSelectedNode(
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps[0].id,
|
||||
);
|
||||
setWorkflowRunId(oneFailedWorkflowRunQueryResult.workflowRun.id);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
RouterDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
WorkspaceDecorator,
|
||||
WorkflowStepDecorator,
|
||||
],
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query('FindOneWorkflowRun', () => {
|
||||
const workflowRunContext =
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.context;
|
||||
|
||||
// Rendering the whole objectMetadata information in the JSON viewer is too long for storybook
|
||||
// so we remove it for the story
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
...oneFailedWorkflowRunQueryResult,
|
||||
workflowRun: {
|
||||
...oneFailedWorkflowRunQueryResult.workflowRun,
|
||||
context: {
|
||||
...workflowRunContext,
|
||||
trigger: {
|
||||
...workflowRunContext.trigger,
|
||||
objectMetadata: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
...graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof RightDrawerWorkflowRunViewStep>;
|
||||
|
||||
export const NodeTab: Story = {};
|
||||
|
||||
export const InputTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await userEvent.click(await canvas.findByRole('button', { name: 'Input' }));
|
||||
|
||||
expect(await canvas.findByText('Trigger')).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const InputTabDisabledForTrigger: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(TRIGGER_STEP_ID);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const inputTab = await canvas.findByRole('button', { name: 'Input' });
|
||||
|
||||
expect(inputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
|
||||
export const InputTabNotExecutedStep: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps.at(-1)!
|
||||
.id,
|
||||
);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const inputTab = await canvas.findByRole('button', { name: 'Input' });
|
||||
|
||||
expect(inputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
|
||||
export const OutputTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await userEvent.click(
|
||||
await canvas.findByRole('button', { name: 'Output' }),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(canvas.queryByText('Create Record')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(await canvas.findByText('result')).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const OutputTabDisabledForTrigger: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(TRIGGER_STEP_ID);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const outputTab = await canvas.findByRole('button', { name: 'Output' });
|
||||
|
||||
expect(outputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
|
||||
export const OutputTabNotExecutedStep: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps.at(-1)!
|
||||
.id,
|
||||
);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const outputTab = await canvas.findByRole('button', { name: 'Output' });
|
||||
|
||||
expect(outputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
@ -1 +1,7 @@
|
||||
export type WorkflowRunTabId = 'node' | 'input' | 'output';
|
||||
export type WorkflowRunTabIdType = 'node' | 'input' | 'output';
|
||||
|
||||
export enum WorkflowRunTabId {
|
||||
NODE = 'node',
|
||||
INPUT = 'input',
|
||||
OUTPUT = 'output',
|
||||
}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { RightDrawerWorkflowSelectActionContent } from '@/workflow/workflow-steps/workflow-actions/components/RightDrawerWorkflowSelectActionContent';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const RightDrawerWorkflowSelectAction = () => {
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
||||
|
||||
if (!isDefined(workflow)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <RightDrawerWorkflowSelectActionContent workflow={workflow} />;
|
||||
};
|
||||
@ -1,45 +0,0 @@
|
||||
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
||||
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
||||
import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
|
||||
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
|
||||
import { MenuItemCommand, useIcons } from 'twenty-ui';
|
||||
import { RightDrawerStepListContainer } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer';
|
||||
import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
|
||||
|
||||
export const RightDrawerWorkflowSelectActionContent = ({
|
||||
workflow,
|
||||
}: {
|
||||
workflow: WorkflowWithCurrentVersion;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
const { createStep } = useCreateStep({
|
||||
workflow,
|
||||
});
|
||||
|
||||
return (
|
||||
<RightDrawerStepListContainer>
|
||||
<RightDrawerWorkflowSelectStepTitle>
|
||||
Records
|
||||
</RightDrawerWorkflowSelectStepTitle>
|
||||
{RECORD_ACTIONS.map((action) => (
|
||||
<MenuItemCommand
|
||||
key={action.type}
|
||||
LeftIcon={getIcon(action.icon)}
|
||||
text={action.label}
|
||||
onClick={() => createStep(action.type)}
|
||||
/>
|
||||
))}
|
||||
<RightDrawerWorkflowSelectStepTitle>
|
||||
Other
|
||||
</RightDrawerWorkflowSelectStepTitle>
|
||||
{OTHER_ACTIONS.map((action) => (
|
||||
<MenuItemCommand
|
||||
key={action.type}
|
||||
LeftIcon={getIcon(action.icon)}
|
||||
text={action.label}
|
||||
onClick={() => createStep(action.type)}
|
||||
/>
|
||||
))}
|
||||
</RightDrawerStepListContainer>
|
||||
);
|
||||
};
|
||||
@ -19,11 +19,13 @@ import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
|
||||
import { TabList } from '@/ui/layout/tab/components/TabList';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionServerlessFunctionFields';
|
||||
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/constants/WorkflowServerlessFunctionTabListComponentId';
|
||||
import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/types/WorkflowServerlessFunctionTabId';
|
||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/utils/getWrongExportedFunctionMarkers';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
@ -77,8 +79,10 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
const theme = useTheme();
|
||||
const { getIcon } = useIcons();
|
||||
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
|
||||
const tabListId = `${WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID}_${serverlessFunctionId}`;
|
||||
const { activeTabId } = useTabList(tabListId);
|
||||
const activeTabId = useRecoilComponentValueV2(
|
||||
activeTabIdComponentState,
|
||||
WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
);
|
||||
const { updateOneServerlessFunction } =
|
||||
useUpdateOneServerlessFunction(serverlessFunctionId);
|
||||
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
||||
@ -267,8 +271,12 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{ id: 'code', title: 'Code', Icon: IconCode },
|
||||
{ id: 'test', title: 'Test', Icon: IconPlayerPlay },
|
||||
{ id: WorkflowServerlessFunctionTabId.CODE, title: 'Code', Icon: IconCode },
|
||||
{
|
||||
id: WorkflowServerlessFunctionTabId.TEST,
|
||||
title: 'Test',
|
||||
Icon: IconPlayerPlay,
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
@ -284,9 +292,11 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
!loading && (
|
||||
<StyledContainer>
|
||||
<StyledTabList
|
||||
tabListInstanceId={tabListId}
|
||||
tabs={tabs}
|
||||
behaveAsLinks={false}
|
||||
componentInstanceId={
|
||||
WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID
|
||||
}
|
||||
/>
|
||||
<WorkflowStepHeader
|
||||
onTitleChange={(newName: string) => {
|
||||
@ -299,7 +309,7 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
disabled={actionOptions.readonly}
|
||||
/>
|
||||
<WorkflowStepBody>
|
||||
{activeTabId === 'code' && (
|
||||
{activeTabId === WorkflowServerlessFunctionTabId.CODE && (
|
||||
<>
|
||||
<WorkflowEditActionServerlessFunctionFields
|
||||
functionInput={functionInput}
|
||||
@ -323,7 +333,7 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
</StyledCodeEditorContainer>
|
||||
</>
|
||||
)}
|
||||
{activeTabId === 'test' && (
|
||||
{activeTabId === WorkflowServerlessFunctionTabId.TEST && (
|
||||
<>
|
||||
<WorkflowEditActionServerlessFunctionFields
|
||||
functionInput={serverlessFunctionTestData.input}
|
||||
@ -352,7 +362,7 @@ export const WorkflowEditActionServerlessFunction = ({
|
||||
</>
|
||||
)}
|
||||
</WorkflowStepBody>
|
||||
{activeTabId === 'test' && (
|
||||
{activeTabId === WorkflowServerlessFunctionTabId.TEST && (
|
||||
<RightDrawerFooter
|
||||
actions={[
|
||||
<CmdEnterActionButton
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
export type WorkflowServerlessFunctionTabIdType = 'code' | 'test';
|
||||
|
||||
export enum WorkflowServerlessFunctionTabId {
|
||||
CODE = 'code',
|
||||
TEST = 'test',
|
||||
}
|
||||
@ -10,10 +10,11 @@ import {
|
||||
import { isBaseOutputSchema } from '@/workflow/workflow-variables/utils/isBaseOutputSchema';
|
||||
import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isRecordOutputSchema';
|
||||
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState';
|
||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
||||
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/constants/WorkflowServerlessFunctionTabListComponentId';
|
||||
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
|
||||
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
|
||||
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
|
||||
@ -26,7 +27,6 @@ import {
|
||||
OverflowingTextWithTooltip,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
|
||||
type WorkflowVariablesDropdownFieldItemsProps = {
|
||||
step: StepOutputSchema;
|
||||
@ -43,8 +43,8 @@ export const WorkflowVariablesDropdownFieldItems = ({
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const { getIcon } = useIcons();
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
const { setActiveTabId } = useTabList(
|
||||
WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||
activeTabIdComponentState,
|
||||
);
|
||||
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilState(
|
||||
workflowDiagramTriggerNodeSelectionState,
|
||||
|
||||
Reference in New Issue
Block a user