Display workflow step header in workflow run input and output tabs (#11102)
- Wrap the content of Workflow View, Workflow Edit, and Workflow Run side panels with a container making them take all the available height - Remove the `StyledContainer` of code steps as it's redundant with the global container - Add the WorkflowStepHeader to the input and output tabs - Make the JSON visualizer take all the available height in input and output tabs - Reuse the WorkflowStepBody component in the input and output tabs as it applies proper background color ## Demo  Fixes https://discord.com/channels/1130383047699738754/1351906809417568376 --------- Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
committed by
GitHub
parent
1c5f3ef5fa
commit
e6dec51ca6
@ -4,6 +4,13 @@ import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hook
|
|||||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
||||||
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
||||||
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
export const CommandMenuWorkflowEditStepContent = ({
|
export const CommandMenuWorkflowEditStepContent = ({
|
||||||
workflow,
|
workflow,
|
||||||
@ -19,12 +26,14 @@ export const CommandMenuWorkflowEditStepContent = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowStepDetail
|
<StyledContainer>
|
||||||
stepId={workflowSelectedNode}
|
<WorkflowStepDetail
|
||||||
trigger={flow.trigger}
|
stepId={workflowSelectedNode}
|
||||||
steps={flow.steps}
|
trigger={flow.trigger}
|
||||||
onActionUpdate={updateStep}
|
steps={flow.steps}
|
||||||
onTriggerUpdate={updateTrigger}
|
onActionUpdate={updateStep}
|
||||||
/>
|
onTriggerUpdate={updateTrigger}
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,17 +20,17 @@ import styled from '@emotion/styled';
|
|||||||
import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui';
|
import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledTabList = styled(TabList)`
|
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
|
||||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledTabList = styled(TabList)`
|
||||||
|
background-color: ${({ theme }) => theme.background.secondary};
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
type TabId = WorkflowRunTabIdType;
|
type TabId = WorkflowRunTabIdType;
|
||||||
|
|
||||||
export const CommandMenuWorkflowRunViewStep = () => {
|
export const CommandMenuWorkflowRunViewStep = () => {
|
||||||
|
|||||||
@ -2,20 +2,30 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
|
|||||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
||||||
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
||||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
export const CommandMenuWorkflowViewStep = () => {
|
export const CommandMenuWorkflowViewStep = () => {
|
||||||
const flow = useFlowOrThrow();
|
const flow = useFlowOrThrow();
|
||||||
const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
|
const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowStepContextProvider
|
<WorkflowStepContextProvider
|
||||||
value={{ workflowVersionId: flow.workflowVersionId }}
|
value={{ workflowVersionId: flow.workflowVersionId }}
|
||||||
>
|
>
|
||||||
<WorkflowStepDetail
|
<StyledContainer>
|
||||||
stepId={workflowSelectedNode}
|
<WorkflowStepDetail
|
||||||
trigger={flow.trigger}
|
stepId={workflowSelectedNode}
|
||||||
steps={flow.steps}
|
trigger={flow.trigger}
|
||||||
readonly
|
steps={flow.steps}
|
||||||
/>
|
readonly
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
</WorkflowStepContextProvider>
|
</WorkflowStepContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,27 +1,29 @@
|
|||||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||||
|
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
|
||||||
|
import { WorkflowRunStepJsonContainer } from '@/workflow/workflow-steps/components/WorkflowRunStepJsonContainer';
|
||||||
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { getWorkflowPreviousStepId } from '@/workflow/workflow-steps/utils/getWorkflowPreviousStep';
|
import { getWorkflowPreviousStepId } from '@/workflow/workflow-steps/utils/getWorkflowPreviousStep';
|
||||||
import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext';
|
import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext';
|
||||||
import { getWorkflowVariablesUsedInStep } from '@/workflow/workflow-steps/utils/getWorkflowVariablesUsedInStep';
|
import { getWorkflowVariablesUsedInStep } from '@/workflow/workflow-steps/utils/getWorkflowVariablesUsedInStep';
|
||||||
import styled from '@emotion/styled';
|
import { getActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow';
|
||||||
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
|
import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import {
|
import {
|
||||||
IconBrackets,
|
IconBrackets,
|
||||||
JsonNestedNode,
|
JsonNestedNode,
|
||||||
JsonTreeContextProvider,
|
JsonTreeContextProvider,
|
||||||
ShouldExpandNodeInitiallyProps,
|
ShouldExpandNodeInitiallyProps,
|
||||||
|
useIcons,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
display: grid;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding-block: ${({ theme }) => theme.spacing(4)};
|
|
||||||
padding-inline: ${({ theme }) => theme.spacing(3)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||||
const { t } = useLingui();
|
const { t, i18n } = useLingui();
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||||
@ -49,6 +51,23 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stepDefinition = getStepDefinitionOrThrow({
|
||||||
|
stepId,
|
||||||
|
trigger: workflowRun.output.flow.trigger,
|
||||||
|
steps: workflowRun.output.flow.steps,
|
||||||
|
});
|
||||||
|
if (stepDefinition?.type !== 'action') {
|
||||||
|
throw new Error('The input tab must be rendered with an action step.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerTitle = stepDefinition.definition.name;
|
||||||
|
const headerIcon = getActionIcon(stepDefinition.definition.type);
|
||||||
|
const headerIconColor = getActionIconColorOrThrow({
|
||||||
|
theme,
|
||||||
|
actionType: stepDefinition.definition.type,
|
||||||
|
});
|
||||||
|
const headerType = getActionHeaderTypeOrThrow(stepDefinition.definition.type);
|
||||||
|
|
||||||
const variablesUsedInStep = getWorkflowVariablesUsedInStep({
|
const variablesUsedInStep = getWorkflowVariablesUsedInStep({
|
||||||
step,
|
step,
|
||||||
});
|
});
|
||||||
@ -69,30 +88,40 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
|||||||
keyPath.startsWith(previousStepId) && depth < 2;
|
keyPath.startsWith(previousStepId) && depth < 2;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<>
|
||||||
<JsonTreeContextProvider
|
<WorkflowStepHeader
|
||||||
value={{
|
disabled
|
||||||
emptyArrayLabel: t`Empty Array`,
|
Icon={getIcon(headerIcon)}
|
||||||
emptyObjectLabel: t`Empty Object`,
|
iconColor={headerIconColor}
|
||||||
emptyStringLabel: t`[empty string]`,
|
initialTitle={headerTitle}
|
||||||
arrowButtonCollapsedLabel: t`Expand`,
|
headerType={i18n._(headerType)}
|
||||||
arrowButtonExpandedLabel: t`Collapse`,
|
/>
|
||||||
shouldHighlightNode: (keyPath) => variablesUsedInStep.has(keyPath),
|
|
||||||
shouldExpandNodeInitially: isFirstNodeDepthOfPreviousStep,
|
<WorkflowRunStepJsonContainer>
|
||||||
}}
|
<JsonTreeContextProvider
|
||||||
>
|
value={{
|
||||||
<JsonNestedNode
|
emptyArrayLabel: t`Empty Array`,
|
||||||
elements={stepContext.map(({ id, name, context }) => ({
|
emptyObjectLabel: t`Empty Object`,
|
||||||
id,
|
emptyStringLabel: t`[empty string]`,
|
||||||
label: name,
|
arrowButtonCollapsedLabel: t`Expand`,
|
||||||
value: context,
|
arrowButtonExpandedLabel: t`Collapse`,
|
||||||
}))}
|
shouldHighlightNode: (keyPath) => variablesUsedInStep.has(keyPath),
|
||||||
Icon={IconBrackets}
|
shouldExpandNodeInitially: isFirstNodeDepthOfPreviousStep,
|
||||||
depth={0}
|
}}
|
||||||
keyPath=""
|
>
|
||||||
emptyElementsText=""
|
<JsonNestedNode
|
||||||
/>
|
elements={stepContext.map(({ id, name, context }) => ({
|
||||||
</JsonTreeContextProvider>
|
id,
|
||||||
</StyledContainer>
|
label: name,
|
||||||
|
value: context,
|
||||||
|
}))}
|
||||||
|
Icon={IconBrackets}
|
||||||
|
depth={0}
|
||||||
|
keyPath=""
|
||||||
|
emptyElementsText=""
|
||||||
|
/>
|
||||||
|
</JsonTreeContextProvider>
|
||||||
|
</WorkflowRunStepJsonContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledWorkflowRunStepJsonContainer = styled(WorkflowStepBody)`
|
||||||
|
grid-template-rows: max-content;
|
||||||
|
gap: 0;
|
||||||
|
display: grid;
|
||||||
|
overflow: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export { StyledWorkflowRunStepJsonContainer as WorkflowRunStepJsonContainer };
|
||||||
@ -1,40 +1,68 @@
|
|||||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||||
import styled from '@emotion/styled';
|
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
|
||||||
|
import { WorkflowRunStepJsonContainer } from '@/workflow/workflow-steps/components/WorkflowRunStepJsonContainer';
|
||||||
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
|
import { getActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow';
|
||||||
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
|
import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { isTwoFirstDepths, JsonTree } from 'twenty-ui';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { isTwoFirstDepths, JsonTree, useIcons } from 'twenty-ui';
|
||||||
const StyledContainer = styled.div`
|
|
||||||
display: grid;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding-block: ${({ theme }) => theme.spacing(4)};
|
|
||||||
padding-inline: ${({ theme }) => theme.spacing(3)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
||||||
|
const { t, i18n } = useLingui();
|
||||||
|
const theme = useTheme();
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||||
|
|
||||||
const { t } = useLingui();
|
|
||||||
|
|
||||||
if (!isDefined(workflowRun?.output?.stepsOutput)) {
|
if (!isDefined(workflowRun?.output?.stepsOutput)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepOutput = workflowRun.output.stepsOutput[stepId];
|
const stepOutput = workflowRun.output.stepsOutput[stepId];
|
||||||
|
|
||||||
|
const stepDefinition = getStepDefinitionOrThrow({
|
||||||
|
stepId,
|
||||||
|
trigger: workflowRun.output.flow.trigger,
|
||||||
|
steps: workflowRun.output.flow.steps,
|
||||||
|
});
|
||||||
|
if (stepDefinition?.type !== 'action') {
|
||||||
|
throw new Error('The output tab must be rendered with an action step.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerTitle = stepDefinition.definition.name;
|
||||||
|
const headerIcon = getActionIcon(stepDefinition.definition.type);
|
||||||
|
const headerIconColor = getActionIconColorOrThrow({
|
||||||
|
theme,
|
||||||
|
actionType: stepDefinition.definition.type,
|
||||||
|
});
|
||||||
|
const headerType = getActionHeaderTypeOrThrow(stepDefinition.definition.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<>
|
||||||
<JsonTree
|
<WorkflowStepHeader
|
||||||
value={stepOutput}
|
disabled
|
||||||
shouldExpandNodeInitially={isTwoFirstDepths}
|
Icon={getIcon(headerIcon)}
|
||||||
emptyArrayLabel={t`Empty Array`}
|
iconColor={headerIconColor}
|
||||||
emptyObjectLabel={t`Empty Object`}
|
initialTitle={headerTitle}
|
||||||
emptyStringLabel={t`[empty string]`}
|
headerType={i18n._(headerType)}
|
||||||
arrowButtonCollapsedLabel={t`Expand`}
|
|
||||||
arrowButtonExpandedLabel={t`Collapse`}
|
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
|
||||||
|
<WorkflowRunStepJsonContainer>
|
||||||
|
<JsonTree
|
||||||
|
value={stepOutput}
|
||||||
|
shouldExpandNodeInitially={isTwoFirstDepths}
|
||||||
|
emptyArrayLabel={t`Empty Array`}
|
||||||
|
emptyObjectLabel={t`Empty Object`}
|
||||||
|
emptyStringLabel={t`[empty string]`}
|
||||||
|
arrowButtonCollapsedLabel={t`Expand`}
|
||||||
|
arrowButtonExpandedLabel={t`Collapse`}
|
||||||
|
/>
|
||||||
|
</WorkflowRunStepJsonContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,8 @@ const StyledWorkflowStepBody = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
padding: ${({ theme }) => theme.spacing(4)};
|
padding-block: ${({ theme }) => theme.spacing(4)};
|
||||||
|
padding-inline: ${({ theme }) => theme.spacing(3)};
|
||||||
row-gap: ${({ theme }) => theme.spacing(6)};
|
row-gap: ${({ theme }) => theme.spacing(6)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -27,9 +27,10 @@ import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-
|
|||||||
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowServerlessFunctionTabListComponentId';
|
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowServerlessFunctionTabListComponentId';
|
||||||
import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowServerlessFunctionTabId';
|
import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowServerlessFunctionTabId';
|
||||||
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Monaco } from '@monaco-editor/react';
|
import { Monaco } from '@monaco-editor/react';
|
||||||
import { editor } from 'monaco-editor';
|
import { editor } from 'monaco-editor';
|
||||||
@ -40,12 +41,6 @@ import { CodeEditor, IconCode, IconPlayerPlay, useIcons } from 'twenty-ui';
|
|||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledCodeEditorContainer = styled.div`
|
const StyledCodeEditorContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -76,7 +71,6 @@ export const WorkflowEditActionServerlessFunction = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionServerlessFunctionProps) => {
|
}: WorkflowEditActionServerlessFunctionProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
|
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
|
||||||
const activeTabId = useRecoilComponentValueV2(
|
const activeTabId = useRecoilComponentValueV2(
|
||||||
@ -287,10 +281,12 @@ export const WorkflowEditActionServerlessFunction = ({
|
|||||||
? action.name
|
? action.name
|
||||||
: 'Code - Serverless Function';
|
: 'Code - Serverless Function';
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!loading && (
|
!loading && (
|
||||||
<StyledContainer>
|
<>
|
||||||
<StyledTabList
|
<StyledTabList
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
behaveAsLinks={false}
|
behaveAsLinks={false}
|
||||||
@ -303,9 +299,9 @@ export const WorkflowEditActionServerlessFunction = ({
|
|||||||
updateAction({ name: newName });
|
updateAction({ name: newName });
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.color.orange}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Code"
|
headerType={headerType}
|
||||||
disabled={actionOptions.readonly}
|
disabled={actionOptions.readonly}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
@ -373,7 +369,7 @@ export const WorkflowEditActionServerlessFunction = ({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledContainer>
|
</>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,8 +7,9 @@ import { INDEX_FILE_PATH } from '@/serverless-functions/constants/IndexFilePath'
|
|||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunctionFields';
|
import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunctionFields';
|
||||||
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Monaco } from '@monaco-editor/react';
|
import { Monaco } from '@monaco-editor/react';
|
||||||
import { editor } from 'monaco-editor';
|
import { editor } from 'monaco-editor';
|
||||||
@ -16,12 +17,6 @@ import { AutoTypings } from 'monaco-editor-auto-typings';
|
|||||||
import { CodeEditor, useIcons } from 'twenty-ui';
|
import { CodeEditor, useIcons } from 'twenty-ui';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledCodeEditorContainer = styled.div`
|
const StyledCodeEditorContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -34,7 +29,6 @@ type WorkflowReadonlyActionServerlessFunctionProps = {
|
|||||||
export const WorkflowReadonlyActionServerlessFunction = ({
|
export const WorkflowReadonlyActionServerlessFunction = ({
|
||||||
action,
|
action,
|
||||||
}: WorkflowReadonlyActionServerlessFunctionProps) => {
|
}: WorkflowReadonlyActionServerlessFunctionProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
|
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
|
||||||
const serverlessFunctionVersion =
|
const serverlessFunctionVersion =
|
||||||
@ -66,18 +60,20 @@ export const WorkflowReadonlyActionServerlessFunction = ({
|
|||||||
? action.name
|
? action.name
|
||||||
: 'Code - Serverless Function';
|
: 'Code - Serverless Function';
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<>
|
||||||
<WorkflowStepHeader
|
<WorkflowStepHeader
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.color.orange}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Code"
|
headerType={headerType}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
@ -99,6 +95,6 @@ export const WorkflowReadonlyActionServerlessFunction = ({
|
|||||||
/>
|
/>
|
||||||
</StyledCodeEditorContainer>
|
</StyledCodeEditorContainer>
|
||||||
</WorkflowStepBody>
|
</WorkflowStepBody>
|
||||||
</StyledContainer>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,9 +7,10 @@ import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOr
|
|||||||
import { WorkflowCreateRecordAction } from '@/workflow/types/Workflow';
|
import { WorkflowCreateRecordAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
||||||
import { JsonValue } from 'type-fest';
|
import { JsonValue } from 'type-fest';
|
||||||
@ -57,7 +58,6 @@ export const WorkflowEditActionCreateRecord = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionCreateRecordProps) => {
|
}: WorkflowEditActionCreateRecordProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
@ -159,6 +159,8 @@ export const WorkflowEditActionCreateRecord = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : `Create Record`;
|
const headerTitle = isDefined(action.name) ? action.name : `Create Record`;
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -174,9 +176,9 @@ export const WorkflowEditActionCreateRecord = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.font.color.tertiary}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Action"
|
headerType={headerType}
|
||||||
disabled={isFormDisabled}
|
disabled={isFormDisabled}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
|
|||||||
@ -3,10 +3,11 @@ import { Select, SelectOption } from '@/ui/input/components/Select';
|
|||||||
import { WorkflowDeleteRecordAction } from '@/workflow/types/Workflow';
|
import { WorkflowDeleteRecordAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
|
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
||||||
import { JsonValue } from 'type-fest';
|
import { JsonValue } from 'type-fest';
|
||||||
@ -34,7 +35,6 @@ export const WorkflowEditActionDeleteRecord = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionDeleteRecordProps) => {
|
}: WorkflowEditActionDeleteRecordProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
@ -108,6 +108,8 @@ export const WorkflowEditActionDeleteRecord = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : `Delete Record`;
|
const headerTitle = isDefined(action.name) ? action.name : `Delete Record`;
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -123,9 +125,9 @@ export const WorkflowEditActionDeleteRecord = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.font.color.tertiary}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Action"
|
headerType={headerType}
|
||||||
disabled={isFormDisabled}
|
disabled={isFormDisabled}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
|
|||||||
@ -2,11 +2,12 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte
|
|||||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||||
import { WorkflowFindRecordsAction } from '@/workflow/types/Workflow';
|
import { WorkflowFindRecordsAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { FormNumberFieldInput } from '@/object-record/record-field/form-types/components/FormNumberFieldInput';
|
import { FormNumberFieldInput } from '@/object-record/record-field/form-types/components/FormNumberFieldInput';
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
@ -33,7 +34,6 @@ export const WorkflowEditActionFindRecords = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionFindRecordsProps) => {
|
}: WorkflowEditActionFindRecordsProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
@ -90,6 +90,8 @@ export const WorkflowEditActionFindRecords = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : `Search Records`;
|
const headerTitle = isDefined(action.name) ? action.name : `Search Records`;
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -105,9 +107,9 @@ export const WorkflowEditActionFindRecords = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.font.color.tertiary}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Action"
|
headerType={headerType}
|
||||||
disabled={isFormDisabled}
|
disabled={isFormDisabled}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
|
|||||||
@ -12,9 +12,10 @@ import { workflowIdState } from '@/workflow/states/workflowIdState';
|
|||||||
import { WorkflowSendEmailAction } from '@/workflow/types/Workflow';
|
import { WorkflowSendEmailAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { IconPlus, useIcons } from 'twenty-ui';
|
import { IconPlus, useIcons } from 'twenty-ui';
|
||||||
@ -47,7 +48,6 @@ export const WorkflowEditActionSendEmail = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionSendEmailProps) => {
|
}: WorkflowEditActionSendEmailProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||||
@ -188,6 +188,9 @@ export const WorkflowEditActionSendEmail = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : 'Send Email';
|
const headerTitle = isDefined(action.name) ? action.name : 'Send Email';
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
const navigate = useNavigateSettings();
|
const navigate = useNavigateSettings();
|
||||||
|
|
||||||
const { closeCommandMenu } = useCommandMenu();
|
const { closeCommandMenu } = useCommandMenu();
|
||||||
@ -206,9 +209,9 @@ export const WorkflowEditActionSendEmail = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.color.blue}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Email"
|
headerType={headerType}
|
||||||
disabled={actionOptions.readonly}
|
disabled={actionOptions.readonly}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||||
import { WorkflowUpdateRecordAction } from '@/workflow/types/Workflow';
|
import { WorkflowUpdateRecordAction } from '@/workflow/types/Workflow';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
||||||
@ -10,6 +9,8 @@ import { FormMultiSelectFieldInput } from '@/object-record/record-field/form-typ
|
|||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
|
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||||
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
import { HorizontalSeparator, useIcons } from 'twenty-ui';
|
||||||
@ -59,7 +60,6 @@ export const WorkflowEditActionUpdateRecord = ({
|
|||||||
action,
|
action,
|
||||||
actionOptions,
|
actionOptions,
|
||||||
}: WorkflowEditActionUpdateRecordProps) => {
|
}: WorkflowEditActionUpdateRecordProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
@ -160,6 +160,8 @@ export const WorkflowEditActionUpdateRecord = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : `Update Record`;
|
const headerTitle = isDefined(action.name) ? action.name : `Update Record`;
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -175,9 +177,9 @@ export const WorkflowEditActionUpdateRecord = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.font.color.tertiary}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Action"
|
headerType={headerType}
|
||||||
disabled={isFormDisabled}
|
disabled={isFormDisabled}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflo
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { expect, fn, userEvent, within } from '@storybook/test';
|
import { expect, fn, userEvent, within } from '@storybook/test';
|
||||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
|
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
|
||||||
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
||||||
@ -50,6 +51,7 @@ const meta: Meta<typeof WorkflowEditActionFindRecords> = {
|
|||||||
SnackBarDecorator,
|
SnackBarDecorator,
|
||||||
RouterDecorator,
|
RouterDecorator,
|
||||||
WorkspaceDecorator,
|
WorkspaceDecorator,
|
||||||
|
I18nFrontDecorator,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { WorkflowStepType } from '@/workflow/types/Workflow';
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
|
||||||
export const OTHER_ACTIONS: Array<{
|
export const OTHER_ACTIONS: Array<{
|
||||||
label: string;
|
label: string;
|
||||||
type: WorkflowStepType;
|
type: Exclude<
|
||||||
|
WorkflowActionType,
|
||||||
|
'CREATE_RECORD' | 'UPDATE_RECORD' | 'DELETE_RECORD' | 'FIND_RECORDS'
|
||||||
|
>;
|
||||||
icon: string;
|
icon: string;
|
||||||
}> = [
|
}> = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { WorkflowStepType } from '@/workflow/types/Workflow';
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
|
||||||
export const RECORD_ACTIONS: Array<{
|
export const RECORD_ACTIONS: Array<{
|
||||||
label: string;
|
label: string;
|
||||||
type: WorkflowStepType;
|
type: Extract<
|
||||||
|
WorkflowActionType,
|
||||||
|
'CREATE_RECORD' | 'UPDATE_RECORD' | 'DELETE_RECORD' | 'FIND_RECORDS'
|
||||||
|
>;
|
||||||
icon: string;
|
icon: string;
|
||||||
}> = [
|
}> = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/Workflo
|
|||||||
import { WorkflowEditActionFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings';
|
import { WorkflowEditActionFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings';
|
||||||
import { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
|
import { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
|
||||||
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
|
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
|
||||||
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
|
import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow';
|
||||||
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
@ -99,6 +101,9 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
|
|
||||||
const headerTitle = isDefined(action.name) ? action.name : `Form`;
|
const headerTitle = isDefined(action.name) ? action.name : `Form`;
|
||||||
const headerIcon = getActionIcon(action.type);
|
const headerIcon = getActionIcon(action.type);
|
||||||
|
const headerIconColor = useActionIconColorOrThrow(action.type);
|
||||||
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
const [selectedField, setSelectedField] = useState<string | null>(null);
|
const [selectedField, setSelectedField] = useState<string | null>(null);
|
||||||
const isFieldSelected = (fieldName: string) => selectedField === fieldName;
|
const isFieldSelected = (fieldName: string) => selectedField === fieldName;
|
||||||
const handleFieldClick = (fieldName: string) => {
|
const handleFieldClick = (fieldName: string) => {
|
||||||
@ -161,9 +166,9 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
Icon={getIcon(headerIcon)}
|
Icon={getIcon(headerIcon)}
|
||||||
iconColor={theme.font.color.tertiary}
|
iconColor={headerIconColor}
|
||||||
initialTitle={headerTitle}
|
initialTitle={headerTitle}
|
||||||
headerType="Action"
|
headerType={headerType}
|
||||||
disabled={actionOptions.readonly}
|
disabled={actionOptions.readonly}
|
||||||
/>
|
/>
|
||||||
<WorkflowStepBody>
|
<WorkflowStepBody>
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
import { getActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
|
export const useActionHeaderTypeOrThrow = (actionType: WorkflowActionType) => {
|
||||||
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
return _(getActionHeaderTypeOrThrow(actionType));
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
|
export const useActionIconColorOrThrow = (actionType: WorkflowActionType) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return getActionIconColorOrThrow({ theme, actionType });
|
||||||
|
};
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
import { msg } from '@lingui/core/macro';
|
||||||
|
import { assertUnreachable } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
export const getActionHeaderTypeOrThrow = (actionType: WorkflowActionType) => {
|
||||||
|
switch (actionType) {
|
||||||
|
case 'CODE':
|
||||||
|
return msg`Code`;
|
||||||
|
case 'CREATE_RECORD':
|
||||||
|
case 'UPDATE_RECORD':
|
||||||
|
case 'DELETE_RECORD':
|
||||||
|
case 'FIND_RECORDS':
|
||||||
|
case 'FORM':
|
||||||
|
return msg`Action`;
|
||||||
|
case 'SEND_EMAIL':
|
||||||
|
return msg`Email`;
|
||||||
|
default:
|
||||||
|
assertUnreachable(actionType, `Unsupported action type: ${actionType}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,7 +1,8 @@
|
|||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
|
import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
|
||||||
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
|
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
|
||||||
|
|
||||||
export const getActionIcon = (actionType: string) => {
|
export const getActionIcon = (actionType: WorkflowActionType) => {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case 'CREATE_RECORD':
|
case 'CREATE_RECORD':
|
||||||
case 'UPDATE_RECORD':
|
case 'UPDATE_RECORD':
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
import { Theme } from '@emotion/react';
|
||||||
|
import { assertUnreachable } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
export const getActionIconColorOrThrow = ({
|
||||||
|
theme,
|
||||||
|
actionType,
|
||||||
|
}: {
|
||||||
|
theme: Theme;
|
||||||
|
actionType: WorkflowActionType;
|
||||||
|
}) => {
|
||||||
|
switch (actionType) {
|
||||||
|
case 'CODE':
|
||||||
|
return theme.color.orange;
|
||||||
|
case 'CREATE_RECORD':
|
||||||
|
case 'UPDATE_RECORD':
|
||||||
|
case 'DELETE_RECORD':
|
||||||
|
case 'FIND_RECORDS':
|
||||||
|
case 'FORM':
|
||||||
|
return theme.font.color.tertiary;
|
||||||
|
case 'SEND_EMAIL':
|
||||||
|
return theme.color.blue;
|
||||||
|
default:
|
||||||
|
assertUnreachable(actionType, `Unsupported action type: ${actionType}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user