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:
committed by
GitHub
parent
15a2cb5141
commit
1ecc5e2bf6
@ -6,13 +6,16 @@ import {
|
||||
within,
|
||||
} from '@storybook/test';
|
||||
import { JsonTree } from '@ui/json-visualizer/components/JsonTree';
|
||||
import { isTwoFirstDepths } from '@ui/json-visualizer/utils/isTwoFirstDepths';
|
||||
|
||||
const meta: Meta<typeof JsonTree> = {
|
||||
title: 'UI/JsonVisualizer/JsonTree',
|
||||
component: JsonTree,
|
||||
args: {
|
||||
shouldExpandNodeInitially: () => true,
|
||||
emptyArrayLabel: 'Empty Array',
|
||||
emptyObjectLabel: 'Empty Object',
|
||||
emptyStringLabel: '[empty string]',
|
||||
arrowButtonCollapsedLabel: 'Expand',
|
||||
arrowButtonExpandedLabel: 'Collapse',
|
||||
},
|
||||
@ -273,6 +276,41 @@ export const ExpandingElementExpandsAllItsDescendants: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const ExpandTwoFirstDepths: Story = {
|
||||
args: {
|
||||
value: {
|
||||
person: {
|
||||
name: 'John Doe',
|
||||
address: {
|
||||
street: '123 Main St',
|
||||
city: 'New York',
|
||||
country: {
|
||||
name: 'USA',
|
||||
code: 'US',
|
||||
},
|
||||
},
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
shouldExpandNodeInitially: isTwoFirstDepths,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const nameElement = await canvas.findByText('name');
|
||||
expect(nameElement).toBeVisible();
|
||||
|
||||
const addressElement = await canvas.findByText('address');
|
||||
expect(addressElement).toBeVisible();
|
||||
|
||||
const streetElement = canvas.queryByText('street');
|
||||
expect(streetElement).not.toBeInTheDocument();
|
||||
|
||||
const countrCodeElement = canvas.queryByText('code');
|
||||
expect(countrCodeElement).not.toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
export const ReallyDeepNestedObject: Story = {
|
||||
args: {
|
||||
value: {
|
||||
|
||||
@ -5,6 +5,7 @@ import { JsonArrow } from '@ui/json-visualizer/components/internal/JsonArrow';
|
||||
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 { ANIMATION } from '@ui/theme';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useState } from 'react';
|
||||
@ -49,9 +50,13 @@ export const JsonNestedNode = ({
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
}) => {
|
||||
const { shouldExpandNodeInitially } = useJsonTreeContextOrThrow();
|
||||
|
||||
const hideRoot = !isDefined(label);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const [isOpen, setIsOpen] = useState(
|
||||
shouldExpandNodeInitially({ keyPath, depth }),
|
||||
);
|
||||
|
||||
const renderedChildren = (
|
||||
<StyledJsonList
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import { isBoolean, isNull, isNumber, isString } from '@sniptt/guards';
|
||||
import {
|
||||
isBoolean,
|
||||
isNonEmptyString,
|
||||
isNull,
|
||||
isNumber,
|
||||
isString,
|
||||
} from '@sniptt/guards';
|
||||
import {
|
||||
IconCheckbox,
|
||||
IconCircleOff,
|
||||
@ -23,7 +29,7 @@ export const JsonNode = ({
|
||||
depth: number;
|
||||
keyPath: string;
|
||||
}) => {
|
||||
const { shouldHighlightNode } = useJsonTreeContextOrThrow();
|
||||
const { shouldHighlightNode, emptyStringLabel } = useJsonTreeContextOrThrow();
|
||||
|
||||
const isHighlighted = shouldHighlightNode?.(keyPath) ?? false;
|
||||
|
||||
@ -31,7 +37,7 @@ export const JsonNode = ({
|
||||
return (
|
||||
<JsonValueNode
|
||||
label={label}
|
||||
valueAsString="[null]"
|
||||
valueAsString="null"
|
||||
Icon={IconCircleOff}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
@ -42,7 +48,7 @@ export const JsonNode = ({
|
||||
return (
|
||||
<JsonValueNode
|
||||
label={label}
|
||||
valueAsString={value}
|
||||
valueAsString={isNonEmptyString(value) ? value : emptyStringLabel}
|
||||
Icon={IconTypography}
|
||||
isHighlighted={isHighlighted}
|
||||
/>
|
||||
|
||||
@ -1,20 +1,27 @@
|
||||
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 { JsonValue } from 'type-fest';
|
||||
|
||||
export const JsonTree = ({
|
||||
value,
|
||||
shouldHighlightNode,
|
||||
shouldExpandNodeInitially,
|
||||
emptyArrayLabel,
|
||||
emptyObjectLabel,
|
||||
emptyStringLabel,
|
||||
arrowButtonCollapsedLabel,
|
||||
arrowButtonExpandedLabel,
|
||||
}: {
|
||||
value: JsonValue;
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
shouldExpandNodeInitially: (
|
||||
params: ShouldExpandNodeInitiallyProps,
|
||||
) => boolean;
|
||||
emptyArrayLabel: string;
|
||||
emptyObjectLabel: string;
|
||||
emptyStringLabel: string;
|
||||
arrowButtonCollapsedLabel: string;
|
||||
arrowButtonExpandedLabel: string;
|
||||
}) => {
|
||||
@ -22,8 +29,10 @@ export const JsonTree = ({
|
||||
<JsonTreeContextProvider
|
||||
value={{
|
||||
shouldHighlightNode,
|
||||
shouldExpandNodeInitially,
|
||||
emptyArrayLabel,
|
||||
emptyObjectLabel,
|
||||
emptyStringLabel,
|
||||
arrowButtonCollapsedLabel,
|
||||
arrowButtonExpandedLabel,
|
||||
}}
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export type ShouldExpandNodeInitiallyProps = { keyPath: string; depth: number };
|
||||
|
||||
export type JsonTreeContextType = {
|
||||
shouldHighlightNode?: (keyPath: string) => boolean;
|
||||
shouldExpandNodeInitially: (
|
||||
params: ShouldExpandNodeInitiallyProps,
|
||||
) => boolean;
|
||||
emptyStringLabel: string;
|
||||
emptyArrayLabel: string;
|
||||
emptyObjectLabel: string;
|
||||
arrowButtonCollapsedLabel: string;
|
||||
|
||||
@ -8,3 +8,4 @@ export * from './components/JsonValueNode';
|
||||
export * from './contexts/JsonTreeContext';
|
||||
export * from './hooks/useJsonTreeContextOrThrow';
|
||||
export * from './utils/isArray';
|
||||
export * from './utils/isTwoFirstDepths';
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
import { ShouldExpandNodeInitiallyProps } from '@ui/json-visualizer/contexts/JsonTreeContext';
|
||||
|
||||
export const isTwoFirstDepths = ({ depth }: ShouldExpandNodeInitiallyProps) =>
|
||||
depth <= 1;
|
||||
Reference in New Issue
Block a user