JSON visualizer: Highlight the parent nodes of in-use nodes (#11373)
https://github.com/user-attachments/assets/5f31023d-b24f-40c8-a061-ffc0d02b63b0 Closes https://github.com/twentyhq/core-team-issues/issues/715
This commit is contained in:
committed by
GitHub
parent
4a4e65fe4a
commit
144a326709
@ -14,6 +14,7 @@ import { useLingui } from '@lingui/react/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconBrackets, useIcons } from 'twenty-ui/display';
|
||||
import {
|
||||
GetJsonNodeHighlighting,
|
||||
JsonNestedNode,
|
||||
JsonTreeContextProvider,
|
||||
ShouldExpandNodeInitiallyProps,
|
||||
@ -70,6 +71,7 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||
const variablesUsedInStep = getWorkflowVariablesUsedInStep({
|
||||
step,
|
||||
});
|
||||
const allVariablesUsedInStep = Array.from(variablesUsedInStep);
|
||||
|
||||
const stepContext = getWorkflowRunStepContext({
|
||||
context: workflowRun.context,
|
||||
@ -80,6 +82,21 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||
throw new Error('The input tab must be rendered with a non-empty context.');
|
||||
}
|
||||
|
||||
const getNodeHighlighting: GetJsonNodeHighlighting = (keyPath: string) => {
|
||||
if (variablesUsedInStep.has(keyPath)) {
|
||||
return 'blue';
|
||||
}
|
||||
|
||||
const isUsedVariableParent = allVariablesUsedInStep.some((variable) =>
|
||||
variable.startsWith(keyPath),
|
||||
);
|
||||
if (isUsedVariableParent) {
|
||||
return 'partial-blue';
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const isFirstNodeDepthOfPreviousStep = ({
|
||||
keyPath,
|
||||
depth,
|
||||
@ -104,8 +121,7 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||
emptyStringLabel: t`[empty string]`,
|
||||
arrowButtonCollapsedLabel: t`Expand`,
|
||||
arrowButtonExpandedLabel: t`Collapse`,
|
||||
getNodeHighlighting: (keyPath) =>
|
||||
variablesUsedInStep.has(keyPath) ? 'blue' : undefined,
|
||||
getNodeHighlighting,
|
||||
shouldExpandNodeInitially: isFirstNodeDepthOfPreviousStep,
|
||||
}}
|
||||
>
|
||||
|
||||
@ -447,6 +447,26 @@ export const BlueHighlighting: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const PartialBlueHighlighting: Story = {
|
||||
args: {
|
||||
value: {
|
||||
name: 'John Doe',
|
||||
age: 30,
|
||||
address: {
|
||||
city: 'Paris',
|
||||
},
|
||||
},
|
||||
getNodeHighlighting: (keyPath: string) =>
|
||||
keyPath === 'address' ? 'partial-blue' : undefined,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const ageElement = await canvas.findByText('age');
|
||||
expect(ageElement).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const RedHighlighting: Story = {
|
||||
args: {
|
||||
value: {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { IconBrackets } from '@ui/display';
|
||||
import { JsonNestedNode } from '@ui/json-visualizer/components/JsonNestedNode';
|
||||
import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
import { JsonArray } from 'type-fest';
|
||||
|
||||
export const JsonArrayNode = ({
|
||||
@ -8,11 +9,13 @@ export const JsonArrayNode = ({
|
||||
value,
|
||||
depth,
|
||||
keyPath,
|
||||
highlighting,
|
||||
}: {
|
||||
label?: string;
|
||||
value: JsonArray;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
highlighting: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
const { emptyArrayLabel } = useJsonTreeContextOrThrow();
|
||||
|
||||
@ -29,6 +32,7 @@ export const JsonArrayNode = ({
|
||||
depth={depth}
|
||||
emptyElementsText={emptyArrayLabel}
|
||||
keyPath={keyPath}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -6,11 +6,12 @@ import { JsonList } from '@ui/json-visualizer/components/internal/JsonList';
|
||||
import { JsonNodeLabel } from '@ui/json-visualizer/components/internal/JsonNodeLabel';
|
||||
import { JsonNode } from '@ui/json-visualizer/components/JsonNode';
|
||||
import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
import { ANIMATION } from '@ui/theme';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useState } from 'react';
|
||||
import { JsonValue } from 'type-fest';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { JsonValue } from 'type-fest';
|
||||
|
||||
const StyledContainer = styled.li`
|
||||
display: grid;
|
||||
@ -41,6 +42,7 @@ export const JsonNestedNode = ({
|
||||
emptyElementsText,
|
||||
depth,
|
||||
keyPath,
|
||||
highlighting,
|
||||
}: {
|
||||
label?: string;
|
||||
Icon: IconComponent;
|
||||
@ -49,6 +51,7 @@ export const JsonNestedNode = ({
|
||||
emptyElementsText: string;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
highlighting?: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
const { shouldExpandNodeInitially } = useJsonTreeContextOrThrow();
|
||||
|
||||
@ -115,7 +118,11 @@ export const JsonNestedNode = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledLabelContainer>
|
||||
<JsonArrow isOpen={isOpen} onClick={handleArrowClick} />
|
||||
<JsonArrow
|
||||
isOpen={isOpen}
|
||||
onClick={handleArrowClick}
|
||||
variant={highlighting === 'partial-blue' ? 'blue' : undefined}
|
||||
/>
|
||||
|
||||
<JsonNodeLabel label={label} Icon={Icon} />
|
||||
|
||||
|
||||
@ -84,6 +84,7 @@ export const JsonNode = ({
|
||||
value={value}
|
||||
depth={depth}
|
||||
keyPath={keyPath}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -94,6 +95,7 @@ export const JsonNode = ({
|
||||
value={value}
|
||||
depth={depth}
|
||||
keyPath={keyPath}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { IconCube } from '@ui/display';
|
||||
import { JsonNestedNode } from '@ui/json-visualizer/components/JsonNestedNode';
|
||||
import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
import { JsonObject } from 'type-fest';
|
||||
|
||||
export const JsonObjectNode = ({
|
||||
@ -8,11 +9,13 @@ export const JsonObjectNode = ({
|
||||
value,
|
||||
depth,
|
||||
keyPath,
|
||||
highlighting,
|
||||
}: {
|
||||
label?: string;
|
||||
value: JsonObject;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
highlighting: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
const { emptyObjectLabel } = useJsonTreeContextOrThrow();
|
||||
|
||||
@ -29,6 +32,7 @@ export const JsonObjectNode = ({
|
||||
depth={depth}
|
||||
emptyElementsText={emptyObjectLabel}
|
||||
keyPath={keyPath}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -27,9 +27,11 @@ const MotionIconChevronDown = motion.create(IconChevronDown);
|
||||
export const JsonArrow = ({
|
||||
isOpen,
|
||||
onClick,
|
||||
variant,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onClick: () => void;
|
||||
variant?: 'blue';
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
@ -44,7 +46,9 @@ export const JsonArrow = ({
|
||||
|
||||
<MotionIconChevronDown
|
||||
size={theme.icon.size.md}
|
||||
color={theme.font.color.secondary}
|
||||
color={
|
||||
variant === 'blue' ? theme.color.blue : theme.font.color.secondary
|
||||
}
|
||||
initial={false}
|
||||
animate={{ rotate: isOpen ? 0 : -90 }}
|
||||
transition={{ duration: ANIMATION.duration.normal }}
|
||||
|
||||
@ -8,7 +8,7 @@ const StyledText = styled.span<{
|
||||
highlighting === 'blue'
|
||||
? theme.adaptiveColors.blue4
|
||||
: highlighting === 'red'
|
||||
? theme.font.color.danger
|
||||
? theme.adaptiveColors.red4
|
||||
: theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { ThemeColor } from '@ui/theme';
|
||||
|
||||
export type JsonNodeHighlighting = Extract<ThemeColor, 'blue' | 'red'>;
|
||||
export type JsonNodeHighlighting =
|
||||
| Extract<ThemeColor, 'blue' | 'red'>
|
||||
| 'partial-blue';
|
||||
|
||||
Reference in New Issue
Block a user