Highlight consumed variables in workflow runs (#10788)
- Create a function to resolve the variables used in the configuration of a step - Let the JSON tree components take a prop (`getNodeHighlighting`) to determine whether an element must be highlighted - Compute each element's keyPath recursively; the keyPath is passed as an argument to the `getNodeHighlighting` function ## Demo https://github.com/user-attachments/assets/8586f43d-53d1-41ba-ab48-08bb8c74e145 Closes https://github.com/twentyhq/core-team-issues/issues/435
This commit is contained in:
committed by
GitHub
parent
7e291f3cff
commit
ecf282ad99
@ -7,10 +7,14 @@ export const JsonArrayNode = ({
|
||||
label,
|
||||
value,
|
||||
depth,
|
||||
keyPath,
|
||||
shouldHighlightNode,
|
||||
}: {
|
||||
label?: string;
|
||||
value: JsonArray;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
@ -26,6 +30,8 @@ export const JsonArrayNode = ({
|
||||
Icon={IconBrackets}
|
||||
depth={depth}
|
||||
emptyElementsText={t`Empty Array`}
|
||||
keyPath={keyPath}
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,6 +3,7 @@ import { JsonList } from '@/workflow/components/json-visualizer/components/inter
|
||||
import { JsonNodeLabel } from '@/workflow/components/json-visualizer/components/internal/JsonNodeLabel';
|
||||
import { JsonNode } from '@/workflow/components/json-visualizer/components/JsonNode';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
@ -35,6 +36,8 @@ export const JsonNestedNode = ({
|
||||
renderElementsCount,
|
||||
emptyElementsText,
|
||||
depth,
|
||||
keyPath,
|
||||
shouldHighlightNode,
|
||||
}: {
|
||||
label?: string;
|
||||
Icon: IconComponent;
|
||||
@ -42,6 +45,8 @@ export const JsonNestedNode = ({
|
||||
renderElementsCount?: (count: number) => string;
|
||||
emptyElementsText: string;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
}) => {
|
||||
const hideRoot = !isDefined(label);
|
||||
|
||||
@ -52,9 +57,22 @@ export const JsonNestedNode = ({
|
||||
{elements.length === 0 ? (
|
||||
<StyledEmptyState>{emptyElementsText}</StyledEmptyState>
|
||||
) : (
|
||||
elements.map(({ id, label, value }) => (
|
||||
<JsonNode key={id} label={label} value={value} depth={depth + 1} />
|
||||
))
|
||||
elements.map(({ id, label, value }) => {
|
||||
const nextKeyPath = isNonEmptyString(keyPath)
|
||||
? `${keyPath}.${id}`
|
||||
: String(id);
|
||||
|
||||
return (
|
||||
<JsonNode
|
||||
key={id}
|
||||
label={label}
|
||||
value={value}
|
||||
depth={depth + 1}
|
||||
keyPath={nextKeyPath}
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</JsonList>
|
||||
);
|
||||
|
||||
@ -15,17 +15,24 @@ export const JsonNode = ({
|
||||
label,
|
||||
value,
|
||||
depth,
|
||||
keyPath,
|
||||
shouldHighlightNode,
|
||||
}: {
|
||||
label?: string;
|
||||
value: JsonValue;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
}) => {
|
||||
const isHighlighted = shouldHighlightNode?.(keyPath) ?? false;
|
||||
|
||||
if (isNull(value)) {
|
||||
return (
|
||||
<JsonValueNode
|
||||
label={label}
|
||||
valueAsString="[null]"
|
||||
Icon={IconCircleOff}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -36,6 +43,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={value}
|
||||
Icon={IconTypography}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -46,6 +54,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={String(value)}
|
||||
Icon={IconNumber9}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -56,13 +65,30 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={String(value)}
|
||||
Icon={IconCheckbox}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return <JsonArrayNode label={label} value={value} depth={depth} />;
|
||||
return (
|
||||
<JsonArrayNode
|
||||
label={label}
|
||||
value={value}
|
||||
depth={depth}
|
||||
keyPath={keyPath}
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <JsonObjectNode label={label} value={value} depth={depth} />;
|
||||
return (
|
||||
<JsonObjectNode
|
||||
label={label}
|
||||
value={value}
|
||||
depth={depth}
|
||||
keyPath={keyPath}
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -7,10 +7,14 @@ export const JsonObjectNode = ({
|
||||
label,
|
||||
value,
|
||||
depth,
|
||||
keyPath,
|
||||
shouldHighlightNode,
|
||||
}: {
|
||||
label?: string;
|
||||
value: JsonObject;
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
@ -26,6 +30,8 @@ export const JsonObjectNode = ({
|
||||
Icon={IconCube}
|
||||
depth={depth}
|
||||
emptyElementsText={t`Empty Object`}
|
||||
keyPath={keyPath}
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,10 +2,21 @@ import { JsonList } from '@/workflow/components/json-visualizer/components/inter
|
||||
import { JsonNode } from '@/workflow/components/json-visualizer/components/JsonNode';
|
||||
import { JsonValue } from 'type-fest';
|
||||
|
||||
export const JsonTree = ({ value }: { value: JsonValue }) => {
|
||||
export const JsonTree = ({
|
||||
value,
|
||||
shouldHighlightNode,
|
||||
}: {
|
||||
value: JsonValue;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
}) => {
|
||||
return (
|
||||
<JsonList depth={0}>
|
||||
<JsonNode value={value} depth={0} />
|
||||
<JsonNode
|
||||
value={value}
|
||||
depth={0}
|
||||
keyPath=""
|
||||
shouldHighlightNode={shouldHighlightNode}
|
||||
/>
|
||||
</JsonList>
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,6 +10,7 @@ const StyledListItem = styled(JsonListItem)`
|
||||
|
||||
type JsonValueNodeProps = {
|
||||
valueAsString: string;
|
||||
isHighlighted: boolean;
|
||||
} & (
|
||||
| {
|
||||
label: string;
|
||||
@ -24,9 +25,18 @@ type JsonValueNodeProps = {
|
||||
export const JsonValueNode = (props: JsonValueNodeProps) => {
|
||||
return (
|
||||
<StyledListItem>
|
||||
{props.label && <JsonNodeLabel label={props.label} Icon={props.Icon} />}
|
||||
{props.label && (
|
||||
<JsonNodeLabel
|
||||
label={props.label}
|
||||
Icon={props.Icon}
|
||||
isHighlighted={props.isHighlighted}
|
||||
/>
|
||||
)}
|
||||
|
||||
<JsonNodeValue valueAsString={props.valueAsString} />
|
||||
<JsonNodeValue
|
||||
valueAsString={props.valueAsString}
|
||||
isHighlighted={props.isHighlighted}
|
||||
/>
|
||||
</StyledListItem>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,10 +2,12 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
const StyledLabelContainer = styled.span`
|
||||
const StyledLabelContainer = styled.span<{ isHighlighted?: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||
border-color: ${({ theme }) => theme.border.color.medium};
|
||||
color: ${({ theme, isHighlighted }) =>
|
||||
isHighlighted ? theme.color.blue : theme.font.color.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
@ -23,15 +25,20 @@ const StyledLabelContainer = styled.span`
|
||||
export const JsonNodeLabel = ({
|
||||
label,
|
||||
Icon,
|
||||
isHighlighted,
|
||||
}: {
|
||||
label: string;
|
||||
Icon: IconComponent;
|
||||
isHighlighted?: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledLabelContainer>
|
||||
<Icon size={theme.icon.size.md} color={theme.font.color.tertiary} />
|
||||
<StyledLabelContainer isHighlighted={isHighlighted}>
|
||||
<Icon
|
||||
size={theme.icon.size.md}
|
||||
color={isHighlighted ? theme.color.blue : theme.font.color.tertiary}
|
||||
/>
|
||||
|
||||
<span>{label}</span>
|
||||
</StyledLabelContainer>
|
||||
|
||||
@ -1,9 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledText = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
const StyledText = styled.span<{ isHighlighted?: boolean }>`
|
||||
color: ${({ theme, isHighlighted }) =>
|
||||
isHighlighted ? theme.adaptiveColors.blue4 : theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
export const JsonNodeValue = ({ valueAsString }: { valueAsString: string }) => {
|
||||
return <StyledText>{valueAsString}</StyledText>;
|
||||
export const JsonNodeValue = ({
|
||||
valueAsString,
|
||||
isHighlighted,
|
||||
}: {
|
||||
valueAsString: string;
|
||||
isHighlighted?: boolean;
|
||||
}) => {
|
||||
return <StyledText isHighlighted={isHighlighted}>{valueAsString}</StyledText>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user