Set failed node's output as red (#11358)
| Error | Success | |--------|--------| |  |  | Closes https://github.com/twentyhq/core-team-issues/issues/716
This commit is contained in:
committed by
GitHub
parent
183dc40916
commit
bea75b9532
@ -11,6 +11,7 @@ import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/
|
||||
import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
IconBrackets,
|
||||
JsonNestedNode,
|
||||
@ -18,7 +19,6 @@ import {
|
||||
ShouldExpandNodeInitiallyProps,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||
const { t, i18n } = useLingui();
|
||||
@ -105,7 +105,8 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => {
|
||||
emptyStringLabel: t`[empty string]`,
|
||||
arrowButtonCollapsedLabel: t`Expand`,
|
||||
arrowButtonExpandedLabel: t`Collapse`,
|
||||
shouldHighlightNode: (keyPath) => variablesUsedInStep.has(keyPath),
|
||||
getNodeHighlighting: (keyPath) =>
|
||||
variablesUsedInStep.has(keyPath) ? 'blue' : undefined,
|
||||
shouldExpandNodeInitially: isFirstNodeDepthOfPreviousStep,
|
||||
}}
|
||||
>
|
||||
|
||||
@ -9,7 +9,12 @@ import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-ac
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isTwoFirstDepths, JsonTree, useIcons } from 'twenty-ui';
|
||||
import {
|
||||
GetJsonNodeHighlighting,
|
||||
isTwoFirstDepths,
|
||||
JsonTree,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
|
||||
export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
||||
const { t, i18n } = useLingui();
|
||||
@ -42,6 +47,8 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
||||
});
|
||||
const headerType = getActionHeaderTypeOrThrow(stepDefinition.definition.type);
|
||||
|
||||
const setRedHighlightingForEveryNode: GetJsonNodeHighlighting = () => 'red';
|
||||
|
||||
return (
|
||||
<>
|
||||
<WorkflowStepHeader
|
||||
@ -61,6 +68,11 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
||||
emptyStringLabel={t`[empty string]`}
|
||||
arrowButtonCollapsedLabel={t`Expand`}
|
||||
arrowButtonExpandedLabel={t`Collapse`}
|
||||
getNodeHighlighting={
|
||||
isDefined(stepOutput.error)
|
||||
? setRedHighlightingForEveryNode
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</WorkflowRunStepJsonContainer>
|
||||
</>
|
||||
|
||||
@ -430,3 +430,35 @@ export const LongText: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const BlueHighlighting: Story = {
|
||||
args: {
|
||||
value: {
|
||||
name: 'John Doe',
|
||||
age: 30,
|
||||
},
|
||||
getNodeHighlighting: () => 'blue',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const ageElement = await canvas.findByText('age');
|
||||
expect(ageElement).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const RedHighlighting: Story = {
|
||||
args: {
|
||||
value: {
|
||||
name: 'John Doe',
|
||||
age: 30,
|
||||
},
|
||||
getNodeHighlighting: () => 'red',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const ageElement = await canvas.findByText('age');
|
||||
expect(ageElement).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
@ -29,9 +29,9 @@ export const JsonNode = ({
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
}) => {
|
||||
const { shouldHighlightNode, emptyStringLabel } = useJsonTreeContextOrThrow();
|
||||
const { getNodeHighlighting, emptyStringLabel } = useJsonTreeContextOrThrow();
|
||||
|
||||
const isHighlighted = shouldHighlightNode?.(keyPath) ?? false;
|
||||
const highlighting = getNodeHighlighting?.(keyPath);
|
||||
|
||||
if (isNull(value)) {
|
||||
return (
|
||||
@ -39,7 +39,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString="null"
|
||||
Icon={IconCircleOff}
|
||||
isHighlighted={isHighlighted}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -50,7 +50,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={isNonEmptyString(value) ? value : emptyStringLabel}
|
||||
Icon={IconTypography}
|
||||
isHighlighted={isHighlighted}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -61,7 +61,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={String(value)}
|
||||
Icon={IconNumber9}
|
||||
isHighlighted={isHighlighted}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -72,7 +72,7 @@ export const JsonNode = ({
|
||||
label={label}
|
||||
valueAsString={String(value)}
|
||||
Icon={IconCheckbox}
|
||||
isHighlighted={isHighlighted}
|
||||
highlighting={highlighting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,11 +2,12 @@ import { JsonList } from '@ui/json-visualizer/components/internal/JsonList';
|
||||
import { JsonNode } from '@ui/json-visualizer/components/JsonNode';
|
||||
import { JsonTreeContextProvider } from '@ui/json-visualizer/components/JsonTreeContextProvider';
|
||||
import { ShouldExpandNodeInitiallyProps } from '@ui/json-visualizer/contexts/JsonTreeContext';
|
||||
import { GetJsonNodeHighlighting } from '@ui/json-visualizer/types/GetJsonNodeHighlighting';
|
||||
import { JsonValue } from 'type-fest';
|
||||
|
||||
export const JsonTree = ({
|
||||
value,
|
||||
shouldHighlightNode,
|
||||
getNodeHighlighting,
|
||||
shouldExpandNodeInitially,
|
||||
emptyArrayLabel,
|
||||
emptyObjectLabel,
|
||||
@ -15,7 +16,7 @@ export const JsonTree = ({
|
||||
arrowButtonExpandedLabel,
|
||||
}: {
|
||||
value: JsonValue;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
getNodeHighlighting?: GetJsonNodeHighlighting;
|
||||
shouldExpandNodeInitially: (
|
||||
params: ShouldExpandNodeInitiallyProps,
|
||||
) => boolean;
|
||||
@ -28,7 +29,7 @@ export const JsonTree = ({
|
||||
return (
|
||||
<JsonTreeContextProvider
|
||||
value={{
|
||||
shouldHighlightNode,
|
||||
getNodeHighlighting,
|
||||
shouldExpandNodeInitially,
|
||||
emptyArrayLabel,
|
||||
emptyObjectLabel,
|
||||
|
||||
@ -3,6 +3,7 @@ import { IconComponent } from '@ui/display';
|
||||
import { JsonListItem } from '@ui/json-visualizer/components/internal/JsonListItem';
|
||||
import { JsonNodeLabel } from '@ui/json-visualizer/components/internal/JsonNodeLabel';
|
||||
import { JsonNodeValue } from '@ui/json-visualizer/components/internal/JsonNodeValue';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
|
||||
const StyledListItem = styled(JsonListItem)`
|
||||
column-gap: ${({ theme }) => theme.spacing(2)};
|
||||
@ -10,7 +11,7 @@ const StyledListItem = styled(JsonListItem)`
|
||||
|
||||
type JsonValueNodeProps = {
|
||||
valueAsString: string;
|
||||
isHighlighted: boolean;
|
||||
highlighting: JsonNodeHighlighting | undefined;
|
||||
} & (
|
||||
| {
|
||||
label: string;
|
||||
@ -29,13 +30,13 @@ export const JsonValueNode = (props: JsonValueNodeProps) => {
|
||||
<JsonNodeLabel
|
||||
label={props.label}
|
||||
Icon={props.Icon}
|
||||
isHighlighted={props.isHighlighted}
|
||||
highlighting={props.highlighting}
|
||||
/>
|
||||
)}
|
||||
|
||||
<JsonNodeValue
|
||||
valueAsString={props.valueAsString}
|
||||
isHighlighted={props.isHighlighted}
|
||||
highlighting={props.highlighting}
|
||||
/>
|
||||
</StyledListItem>
|
||||
);
|
||||
|
||||
@ -1,13 +1,30 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconComponent } from '@ui/display';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
|
||||
const StyledLabelContainer = styled.span<{ isHighlighted?: boolean }>`
|
||||
const StyledLabelContainer = styled.span<{
|
||||
highlighting?: JsonNodeHighlighting;
|
||||
}>`
|
||||
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};
|
||||
background-color: ${({ theme, highlighting }) =>
|
||||
highlighting === 'blue'
|
||||
? theme.adaptiveColors.blue1
|
||||
: highlighting === 'red'
|
||||
? theme.background.danger
|
||||
: theme.background.transparent.lighter};
|
||||
border-color: ${({ theme, highlighting }) =>
|
||||
highlighting === 'blue'
|
||||
? theme.adaptiveColors.blue2
|
||||
: highlighting === 'red'
|
||||
? theme.border.color.danger
|
||||
: theme.border.color.medium};
|
||||
color: ${({ theme, highlighting }) =>
|
||||
highlighting === 'blue'
|
||||
? theme.color.blue
|
||||
: highlighting === 'red'
|
||||
? theme.font.color.danger
|
||||
: theme.font.color.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
@ -25,19 +42,25 @@ const StyledLabelContainer = styled.span<{ isHighlighted?: boolean }>`
|
||||
export const JsonNodeLabel = ({
|
||||
label,
|
||||
Icon,
|
||||
isHighlighted,
|
||||
highlighting,
|
||||
}: {
|
||||
label: string;
|
||||
Icon: IconComponent;
|
||||
isHighlighted?: boolean;
|
||||
highlighting?: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledLabelContainer isHighlighted={isHighlighted}>
|
||||
<StyledLabelContainer highlighting={highlighting}>
|
||||
<Icon
|
||||
size={theme.icon.size.md}
|
||||
color={isHighlighted ? theme.color.blue : theme.font.color.tertiary}
|
||||
color={
|
||||
highlighting === 'blue'
|
||||
? theme.color.blue
|
||||
: highlighting === 'red'
|
||||
? theme.font.color.danger
|
||||
: theme.font.color.tertiary
|
||||
}
|
||||
/>
|
||||
|
||||
<span>{label}</span>
|
||||
|
||||
@ -1,16 +1,23 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
|
||||
const StyledText = styled.span<{ isHighlighted?: boolean }>`
|
||||
color: ${({ theme, isHighlighted }) =>
|
||||
isHighlighted ? theme.adaptiveColors.blue4 : theme.font.color.tertiary};
|
||||
const StyledText = styled.span<{
|
||||
highlighting: JsonNodeHighlighting | undefined;
|
||||
}>`
|
||||
color: ${({ theme, highlighting }) =>
|
||||
highlighting === 'blue'
|
||||
? theme.adaptiveColors.blue4
|
||||
: highlighting === 'red'
|
||||
? theme.font.color.danger
|
||||
: theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
export const JsonNodeValue = ({
|
||||
valueAsString,
|
||||
isHighlighted,
|
||||
highlighting,
|
||||
}: {
|
||||
valueAsString: string;
|
||||
isHighlighted?: boolean;
|
||||
highlighting?: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
return <StyledText isHighlighted={isHighlighted}>{valueAsString}</StyledText>;
|
||||
return <StyledText highlighting={highlighting}>{valueAsString}</StyledText>;
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { GetJsonNodeHighlighting } from '@ui/json-visualizer/types/GetJsonNodeHighlighting';
|
||||
import { createContext } from 'react';
|
||||
|
||||
export type ShouldExpandNodeInitiallyProps = { keyPath: string; depth: number };
|
||||
|
||||
export type JsonTreeContextType = {
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
getNodeHighlighting?: GetJsonNodeHighlighting;
|
||||
shouldExpandNodeInitially: (
|
||||
params: ShouldExpandNodeInitiallyProps,
|
||||
) => boolean;
|
||||
|
||||
@ -7,5 +7,7 @@ export * from './components/JsonTreeContextProvider';
|
||||
export * from './components/JsonValueNode';
|
||||
export * from './contexts/JsonTreeContext';
|
||||
export * from './hooks/useJsonTreeContextOrThrow';
|
||||
export * from './types/GetJsonNodeHighlighting';
|
||||
export * from './types/JsonNodeHighlighting';
|
||||
export * from './utils/isArray';
|
||||
export * from './utils/isTwoFirstDepths';
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
import { JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
|
||||
export type GetJsonNodeHighlighting = (
|
||||
keyPath: string,
|
||||
) => JsonNodeHighlighting | undefined;
|
||||
@ -0,0 +1,3 @@
|
||||
import { ThemeColor } from '@ui/theme';
|
||||
|
||||
export type JsonNodeHighlighting = Extract<ThemeColor, 'blue' | 'red'>;
|
||||
Reference in New Issue
Block a user