Limit nodes opened by default in the JSON Tree component (#11002)

- Add a parameter to choose which nodes to open by default
- On the Admin Panel, open all nodes by default
- On the Workflow Run step output, open only the two first depths
- On the Workflow Run step input, open only the previous step first
depth
- Display `[empty string]` when a node is an empty string
- Now, display `null` instead of `[null]`

## Demo


https://github.com/user-attachments/assets/99b3078a-da3c-4330-b0ff-ddb2e360d933

Closes https://github.com/twentyhq/core-team-issues/issues/538
This commit is contained in:
Baptiste Devessier
2025-03-19 11:44:34 +01:00
committed by GitHub
parent 15a2cb5141
commit 1ecc5e2bf6
13 changed files with 141 additions and 11 deletions

View File

@ -85,11 +85,17 @@ export const RightDrawerWorkflowRunViewStep = () => {
) : null}
{activeTabId === 'input' ? (
<WorkflowRunStepInputDetail stepId={workflowSelectedNode} />
<WorkflowRunStepInputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
{activeTabId === 'output' ? (
<WorkflowRunStepOutputDetail stepId={workflowSelectedNode} />
<WorkflowRunStepOutputDetail
key={workflowSelectedNode}
stepId={workflowSelectedNode}
/>
) : null}
</WorkflowStepContextProvider>
);

View File

@ -1,5 +1,6 @@
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
import { getWorkflowPreviousStepId } from '@/workflow/workflow-steps/utils/getWorkflowPreviousStep';
import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext';
import { getWorkflowVariablesUsedInStep } from '@/workflow/workflow-steps/utils/getWorkflowVariablesUsedInStep';
import styled from '@emotion/styled';
@ -9,6 +10,7 @@ import {
IconBrackets,
JsonNestedNode,
JsonTreeContextProvider,
ShouldExpandNodeInitiallyProps,
} from 'twenty-ui';
const StyledContainer = styled.div`
@ -38,6 +40,15 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
return null;
}
const previousStepId = getWorkflowPreviousStepId({
stepId,
steps: workflowRun.output.flow.steps,
});
if (previousStepId === undefined) {
return null;
}
const variablesUsedInStep = getWorkflowVariablesUsedInStep({
step,
});
@ -47,20 +58,27 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
flow: workflowRun.output.flow,
stepId,
});
if (stepContext.length === 0) {
throw new Error('The input tab must be rendered with a non-empty context.');
}
const isFirstNodeDepthOfPreviousStep = ({
keyPath,
depth,
}: ShouldExpandNodeInitiallyProps) =>
keyPath.startsWith(previousStepId) && depth < 2;
return (
<StyledContainer>
<JsonTreeContextProvider
value={{
emptyArrayLabel: t`Empty Array`,
emptyObjectLabel: t`Empty Object`,
emptyStringLabel: t`[empty string]`,
arrowButtonCollapsedLabel: t`Expand`,
arrowButtonExpandedLabel: t`Collapse`,
shouldHighlightNode: (keyPath) => variablesUsedInStep.has(keyPath),
shouldExpandNodeInitially: isFirstNodeDepthOfPreviousStep,
}}
>
<JsonNestedNode

View File

@ -3,7 +3,7 @@ import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThro
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { isDefined } from 'twenty-shared';
import { JsonTree } from 'twenty-ui';
import { isTwoFirstDepths, JsonTree } from 'twenty-ui';
const StyledContainer = styled.div`
display: grid;
@ -28,8 +28,10 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
<StyledContainer>
<JsonTree
value={stepOutput}
shouldExpandNodeInitially={isTwoFirstDepths}
emptyArrayLabel={t`Empty Array`}
emptyObjectLabel={t`Empty Object`}
emptyStringLabel={t`[empty string]`}
arrowButtonCollapsedLabel={t`Expand`}
arrowButtonExpandedLabel={t`Collapse`}
/>

View File

@ -0,0 +1,25 @@
import { WorkflowStep } from '@/workflow/types/Workflow';
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
export const getWorkflowPreviousStepId = ({
stepId,
steps,
}: {
stepId: string;
steps: Array<WorkflowStep>;
}) => {
if (stepId === TRIGGER_STEP_ID) {
return undefined;
}
if (stepId === steps[0].id) {
return TRIGGER_STEP_ID;
}
const stepIndex = steps.findIndex((step) => step.id === stepId);
if (stepIndex === -1) {
throw new Error('Step not found');
}
return steps[stepIndex - 1].id;
};