Handle JSON viewer empty states (#10750)

- Display the number of descendants for object and array elements
- Display an empty state for arrays and objects
- Make the input and output visualizer scrollable horizontally 
  - Prevent JSON visualizer's text to wrap

## Demo: input


https://github.com/user-attachments/assets/d6bd6acf-a779-4fc7-a8b1-12b857cee7f9

Closes https://github.com/twentyhq/core-team-issues/issues/497
This commit is contained in:
Baptiste Devessier
2025-03-10 17:39:49 +01:00
committed by GitHub
parent dc55fac1d5
commit dd26001372
70 changed files with 533 additions and 39 deletions

View File

@ -1218,6 +1218,14 @@ msgstr "Werknemers"
msgid "Empty"
msgstr "Leeg"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Eindpunt URL"

View File

@ -1218,6 +1218,14 @@ msgstr "الموظفون"
msgid "Empty"
msgstr "فارغ"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "عنوان URL للواجهة النهائية"

View File

@ -1221,6 +1221,14 @@ msgstr "Empleats"
msgid "Empty"
msgstr "Buit"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL de l'endpoint"

View File

@ -1218,6 +1218,14 @@ msgstr "Zaměstnanci"
msgid "Empty"
msgstr "Prázdné"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL koncového bodu"

View File

@ -1221,6 +1221,14 @@ msgstr "Medarbejdere"
msgid "Empty"
msgstr "Tom"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Endpoint-URL"

View File

@ -1221,6 +1221,14 @@ msgstr "Mitarbeiter"
msgid "Empty"
msgstr "Leer"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Endpunkt-URL"

View File

@ -1221,6 +1221,14 @@ msgstr "Εργαζόμενοι"
msgid "Empty"
msgstr "Κενό"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL τελικού σημείου"

View File

@ -1216,6 +1216,14 @@ msgstr "Employees"
msgid "Empty"
msgstr "Empty"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr "Empty Array"
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr "Empty Object"
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Endpoint URL"

View File

@ -1221,6 +1221,14 @@ msgstr "Empleados"
msgid "Empty"
msgstr "Vacío"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL del endpoint"

View File

@ -1218,6 +1218,14 @@ msgstr "Ty\\u00f6ntekij\\u00e4t"
msgid "Empty"
msgstr "Tyhj\\u00e4"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "P\\u00e4\\u00e4tetunnisteen URL"

View File

@ -1218,6 +1218,14 @@ msgstr "Employés"
msgid "Empty"
msgstr "Vide"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL du point de terminaison"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1218,6 +1218,14 @@ msgstr "עובדים"
msgid "Empty"
msgstr "ריק"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL של נקודת קצה"

View File

@ -1221,6 +1221,14 @@ msgstr "Alkalmazottak"
msgid "Empty"
msgstr "\\u00dcres"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "V\\u00e9gpont URL"

View File

@ -1218,6 +1218,14 @@ msgstr "Dipendenti"
msgid "Empty"
msgstr "Vuoto"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL endpoint"

View File

@ -1218,6 +1218,14 @@ msgstr "従業員"
msgid "Empty"
msgstr "空"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "エンドポイントURL"

View File

@ -1218,6 +1218,14 @@ msgstr "직원"
msgid "Empty"
msgstr "비어 있음"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "엔드포인트 URL"

View File

@ -1218,6 +1218,14 @@ msgstr "Werknemers"
msgid "Empty"
msgstr "Leeg"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Endpoint-URL"

View File

@ -1221,6 +1221,14 @@ msgstr "Ansatte"
msgid "Empty"
msgstr "Tom"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Endepunkts-URL"

View File

@ -1218,6 +1218,14 @@ msgstr "Pracownicy"
msgid "Empty"
msgstr "Puste"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL punktu końcowego"

View File

@ -1213,6 +1213,14 @@ msgstr ""
msgid "Empty"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr ""

View File

@ -1218,6 +1218,14 @@ msgstr "Funcionários"
msgid "Empty"
msgstr "Vazio"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL do endpoint"

View File

@ -1221,6 +1221,14 @@ msgstr "Funcionários"
msgid "Empty"
msgstr "Vazio"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL do Endpoint"

View File

@ -1218,6 +1218,14 @@ msgstr "Angajați"
msgid "Empty"
msgstr "Gol"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL endpoint"

View File

@ -1218,6 +1218,14 @@ msgstr "Запослени"
msgid "Empty"
msgstr "Празно"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Ендпоинт УРЛ"

View File

@ -1218,6 +1218,14 @@ msgstr "Anställda"
msgid "Empty"
msgstr "Tom"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Slutpunkts-URL"

View File

@ -1218,6 +1218,14 @@ msgstr "Çalışanlar"
msgid "Empty"
msgstr "Boş"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "Uç Noktası URL"

View File

@ -1271,6 +1271,14 @@ msgstr ""
msgid "Empty"
msgstr "Порожньо"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr ""

View File

@ -1221,6 +1221,14 @@ msgstr "Nhân viên"
msgid "Empty"
msgstr "Trống"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "URL điểm cuối"

View File

@ -1218,6 +1218,14 @@ msgstr "员工"
msgid "Empty"
msgstr "空"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "端点 URL"

View File

@ -1218,6 +1218,14 @@ msgstr "員工"
msgid "Empty"
msgstr "空"
#: src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx
msgid "Empty Array"
msgstr ""
#: src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx
msgid "Empty Object"
msgstr ""
#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
msgid "Endpoint URL"
msgstr "端點 URL"

View File

@ -7,6 +7,7 @@ import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThro
import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext';
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';
@ -39,7 +40,7 @@ export const CommandMenuWorkflowRunViewStep = () => {
})
: undefined;
const isInputTabDisabled =
const areInputAndOutputTabsDisabled =
workflowSelectedNode === TRIGGER_STEP_ID ||
stepExecutionStatus === 'running' ||
stepExecutionStatus === 'not-executed';
@ -50,9 +51,14 @@ export const CommandMenuWorkflowRunViewStep = () => {
id: 'input',
title: 'Input',
Icon: IconLogin2,
disabled: isInputTabDisabled,
disabled: areInputAndOutputTabsDisabled,
},
{
id: 'output',
title: 'Output',
Icon: IconLogout,
disabled: areInputAndOutputTabsDisabled,
},
{ id: 'output', title: 'Output', Icon: IconLogout },
];
if (!isDefined(workflowRun)) {
@ -83,6 +89,10 @@ export const CommandMenuWorkflowRunViewStep = () => {
{activeTabId === 'input' ? (
<WorkflowRunStepInputDetail stepId={workflowSelectedNode} />
) : null}
{activeTabId === 'output' ? (
<WorkflowRunStepOutputDetail stepId={workflowSelectedNode} />
) : null}
</WorkflowVersionComponentInstanceContext.Provider>
);
};

View File

@ -6,7 +6,6 @@ import {
waitForElementToBeRemoved,
within,
} from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
const meta: Meta<typeof JsonTree> = {
@ -14,7 +13,7 @@ const meta: Meta<typeof JsonTree> = {
component: JsonTree,
args: {},
argTypes: {},
decorators: [ComponentDecorator, I18nFrontDecorator],
decorators: [I18nFrontDecorator],
};
export default meta;
@ -51,10 +50,47 @@ export const ArraySimple: Story = {
},
};
export const ArrayEmpty: Story = {
args: {
value: [],
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const emptyState = await canvas.findByText('Empty Array');
expect(emptyState).toBeVisible();
},
};
export const ArrayNested: Story = {
args: {
value: [1, 2, ['a', 'b', 'c'], 3],
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const nestedArrayElements = await canvas.findByText('[3]');
expect(nestedArrayElements).toBeVisible();
},
};
export const ArrayNestedEmpty: Story = {
args: {
value: [1, 2, [], 3],
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const nestedArrayElements = await canvas.findByText('[0]');
expect(nestedArrayElements).toBeVisible();
const emptyState = await canvas.findByText('Empty Array');
expect(emptyState).toBeVisible();
},
};
export const ArrayWithObjects: Story = {
@ -70,6 +106,13 @@ export const ArrayWithObjects: Story = {
},
],
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const nestedObjectItemsCounts = await canvas.findAllByText('{2}');
expect(nestedObjectItemsCounts).toHaveLength(2);
},
};
export const ObjectSimple: Story = {
@ -81,6 +124,19 @@ export const ObjectSimple: Story = {
},
};
export const ObjectEmpty: Story = {
args: {
value: {},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const emptyState = await canvas.findByText('Empty Object');
expect(emptyState).toBeVisible();
},
};
export const ObjectNested: Story = {
args: {
value: {
@ -94,6 +150,32 @@ export const ObjectNested: Story = {
isActive: true,
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const nestedObjectItemsCounts = await canvas.findAllByText('{2}');
expect(nestedObjectItemsCounts).toHaveLength(2);
},
};
export const ObjectNestedEmpty: Story = {
args: {
value: {
person: {},
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const nestedObjectItemsCount = await canvas.findByText('{0}');
expect(nestedObjectItemsCount).toBeVisible();
const emptyState = await canvas.findByText('Empty Object');
expect(emptyState).toBeVisible();
},
};
export const ObjectWithArray: Story = {
@ -187,3 +269,123 @@ export const ExpandingElementExpandsAllItsDescendants: Story = {
}
},
};
export const ReallyDeepNestedObject: Story = {
args: {
value: {
a: {
b: {
c: {
d: {
e: {
f: {
g: {
h: {
i: {
j: {
k: {
l: {
m: {
n: {
o: {
p: {
q: {
r: {
s: {
t: {
u: {
v: {
w: {
x: {
y: {
z: {
end: true,
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
bis: {
c: {
d: {
e: {
f: {
g: {
h: {
i: {
j: {
k: {
l: {
m: {
n: {
o: {
p: {
q: {
r: {
s: {
t: {
u: {
v: {
w: {
x: {
y: {
z: {
end: true,
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
};
export const LongText: Story = {
args: {
value: {
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum iaculis est tincidunt, sagittis neque vitae, sodales purus.':
'Ut lobortis ultricies purus, sit amet porta eros. Suspendisse efficitur quam vitae diam imperdiet feugiat. Etiam vel bibendum elit.',
},
},
};

View File

@ -1,4 +1,5 @@
import { JsonNestedNode } from '@/workflow/components/json-visualizer/components/JsonNestedNode';
import { useLingui } from '@lingui/react/macro';
import { IconBrackets } from 'twenty-ui';
import { JsonArray } from 'type-fest';
@ -11,6 +12,8 @@ export const JsonArrayNode = ({
value: JsonArray;
depth: number;
}) => {
const { t } = useLingui();
return (
<JsonNestedNode
elements={[...value.entries()].map(([key, value]) => ({
@ -18,9 +21,11 @@ export const JsonArrayNode = ({
label: String(key),
value,
}))}
renderElementsCount={(count) => `[${count}]`}
label={label}
Icon={IconBrackets}
depth={depth}
emptyElementsText={t`Empty Array`}
/>
);
};

View File

@ -20,15 +20,27 @@ const StyledLabelContainer = styled.div`
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledElementsCount = styled.span`
color: ${({ theme }) => theme.font.color.tertiary};
`;
const StyledEmptyState = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
`;
export const JsonNestedNode = ({
label,
Icon,
elements,
renderElementsCount,
emptyElementsText,
depth,
}: {
label?: string;
Icon: IconComponent;
elements: Array<{ id: string | number; label: string; value: JsonValue }>;
renderElementsCount?: (count: number) => string;
emptyElementsText: string;
depth: number;
}) => {
const hideRoot = !isDefined(label);
@ -37,9 +49,13 @@ export const JsonNestedNode = ({
const renderedChildren = (
<JsonList depth={depth}>
{elements.map(({ id, label, value }) => (
<JsonNode key={id} label={label} value={value} depth={depth + 1} />
))}
{elements.length === 0 ? (
<StyledEmptyState>{emptyElementsText}</StyledEmptyState>
) : (
elements.map(({ id, label, value }) => (
<JsonNode key={id} label={label} value={value} depth={depth + 1} />
))
)}
</JsonList>
);
@ -57,6 +73,12 @@ export const JsonNestedNode = ({
<JsonArrow isOpen={isOpen} onClick={handleArrowClick} />
<JsonNodeLabel label={label} Icon={Icon} />
{renderElementsCount && (
<StyledElementsCount>
{renderElementsCount(elements.length)}
</StyledElementsCount>
)}
</StyledLabelContainer>
{isOpen && renderedChildren}

View File

@ -1,4 +1,5 @@
import { JsonNestedNode } from '@/workflow/components/json-visualizer/components/JsonNestedNode';
import { useLingui } from '@lingui/react/macro';
import { IconCube } from 'twenty-ui';
import { JsonObject } from 'type-fest';
@ -11,6 +12,8 @@ export const JsonObjectNode = ({
value: JsonObject;
depth: number;
}) => {
const { t } = useLingui();
return (
<JsonNestedNode
elements={Object.entries(value).map(([key, value]) => ({
@ -18,9 +21,11 @@ export const JsonObjectNode = ({
label: key,
value,
}))}
renderElementsCount={(count) => `{${count}}`}
label={label}
Icon={IconCube}
depth={depth}
emptyElementsText={t`Empty Object`}
/>
);
};

View File

@ -4,6 +4,7 @@ const StyledListItem = styled.li`
align-items: center;
display: flex;
list-style-type: none;
white-space: nowrap;
`;
export { StyledListItem as JsonListItem };

View File

@ -7,6 +7,8 @@ import { isDefined } from 'twenty-shared';
import { IconBrackets } from 'twenty-ui';
const StyledContainer = styled.div`
display: grid;
overflow-x: auto;
padding-block: ${({ theme }) => theme.spacing(4)};
padding-inline: ${({ theme }) => theme.spacing(3)};
`;
@ -31,6 +33,10 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
stepId,
});
if (stepContext.length === 0) {
throw new Error('The input tab must be rendered with a non-empty context.');
}
return (
<StyledContainer>
<JsonNestedNode
@ -40,6 +46,7 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
value: context,
}))}
Icon={IconBrackets}
emptyElementsText=""
depth={0}
/>
</StyledContainer>

View File

@ -5,6 +5,8 @@ import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared';
const StyledContainer = styled.div`
display: grid;
overflow-x: auto;
padding-block: ${({ theme }) => theme.spacing(4)};
padding-inline: ${({ theme }) => theme.spacing(3)};
`;