From 093d6c0a1af682843d12f2bf1d2696a3bbccac4e Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Mon, 17 Mar 2025 16:00:06 +0100 Subject: [PATCH] Extract the JSON visualizer component in twenty-ui (#10937) - Move the JsonTree component and the other components to twenty-ui - Rely on a React Context to provide translations ## Future work It would be good to migrate the `createRequiredContext` function to `twenty-ui`. I didn't want to migrate it in this PR but would have liked to use it. --- .../JsonDataIndicatorHealthStatus.tsx | 14 ++++-- .../json-visualizer/components/JsonTree.tsx | 22 ---------- .../components/WorkflowRunStepInputDetail.tsx | 43 +++++++++++++------ .../WorkflowRunStepOutputDetail.tsx | 13 +++++- packages/twenty-ui/src/index.ts | 1 + .../__stories__/JsonTree.stories.tsx | 13 +++--- .../components/JsonArrayNode.tsx | 13 +++--- .../components/JsonNestedNode.tsx | 13 +++--- .../json-visualizer/components/JsonNode.tsx | 17 ++++---- .../components/JsonObjectNode.tsx | 13 +++--- .../json-visualizer/components/JsonTree.tsx | 36 ++++++++++++++++ .../components/JsonTreeContextProvider.tsx | 18 ++++++++ .../components/JsonValueNode.tsx | 8 ++-- .../components/internal/JsonArrow.tsx | 14 +++--- .../components/internal/JsonList.tsx | 0 .../components/internal/JsonListItem.tsx | 0 .../components/internal/JsonNodeLabel.tsx | 2 +- .../components/internal/JsonNodeValue.tsx | 0 .../contexts/JsonTreeContext.tsx | 13 ++++++ .../hooks/useJsonTreeContextOrThrow.tsx | 15 +++++++ .../twenty-ui/src/json-visualizer/index.ts | 10 +++++ .../src}/json-visualizer/utils/isArray.ts | 0 22 files changed, 189 insertions(+), 89 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonTree.tsx rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/__stories__/JsonTree.stories.tsx (97%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/JsonArrayNode.tsx (57%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/JsonNestedNode.tsx (80%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/JsonNode.tsx (72%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/JsonObjectNode.tsx (57%) create mode 100644 packages/twenty-ui/src/json-visualizer/components/JsonTree.tsx create mode 100644 packages/twenty-ui/src/json-visualizer/components/JsonTreeContextProvider.tsx rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/JsonValueNode.tsx (67%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/internal/JsonArrow.tsx (71%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/internal/JsonList.tsx (100%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/internal/JsonListItem.tsx (100%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/internal/JsonNodeLabel.tsx (96%) rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/components/internal/JsonNodeValue.tsx (100%) create mode 100644 packages/twenty-ui/src/json-visualizer/contexts/JsonTreeContext.tsx create mode 100644 packages/twenty-ui/src/json-visualizer/hooks/useJsonTreeContextOrThrow.tsx create mode 100644 packages/twenty-ui/src/json-visualizer/index.ts rename packages/{twenty-front/src/modules/workflow/components => twenty-ui/src}/json-visualizer/utils/isArray.ts (100%) diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx index 7d2de522d..68f594c0c 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx @@ -1,8 +1,8 @@ import { SettingsAdminIndicatorHealthContext } from '@/settings/admin-panel/health-status/contexts/SettingsAdminIndicatorHealthContext'; -import { JsonTree } from '@/workflow/components/json-visualizer/components/JsonTree'; import styled from '@emotion/styled'; +import { useLingui } from '@lingui/react/macro'; import { useContext } from 'react'; -import { Section } from 'twenty-ui'; +import { JsonTree, Section } from 'twenty-ui'; import { AdminPanelHealthServiceStatus } from '~/generated/graphql'; const StyledDetailsContainer = styled.div` @@ -21,6 +21,8 @@ const StyledErrorMessage = styled.div` `; export const JsonDataIndicatorHealthStatus = () => { + const { t } = useLingui(); + const { indicatorHealth } = useContext(SettingsAdminIndicatorHealthContext); const parsedDetails = indicatorHealth.details @@ -41,7 +43,13 @@ export const JsonDataIndicatorHealthStatus = () => { )} {parsedDetails && ( - + )} diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonTree.tsx b/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonTree.tsx deleted file mode 100644 index 43c474a1f..000000000 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonTree.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { JsonList } from '@/workflow/components/json-visualizer/components/internal/JsonList'; -import { JsonNode } from '@/workflow/components/json-visualizer/components/JsonNode'; -import { JsonValue } from 'type-fest'; - -export const JsonTree = ({ - value, - shouldHighlightNode, -}: { - value: JsonValue; - shouldHighlightNode?: (keyPath: string) => boolean; -}) => { - return ( - - - - ); -}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx index f1bee4ca5..c703fb2ad 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx @@ -1,11 +1,15 @@ -import { JsonNestedNode } from '@/workflow/components/json-visualizer/components/JsonNestedNode'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext'; import { getWorkflowVariablesUsedInStep } from '@/workflow/workflow-steps/utils/getWorkflowVariablesUsedInStep'; import styled from '@emotion/styled'; +import { useLingui } from '@lingui/react/macro'; import { isDefined } from 'twenty-shared'; -import { IconBrackets } from 'twenty-ui'; +import { + IconBrackets, + JsonNestedNode, + JsonTreeContextProvider, +} from 'twenty-ui'; const StyledContainer = styled.div` display: grid; @@ -15,6 +19,8 @@ const StyledContainer = styled.div` `; export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { + const { t } = useLingui(); + const workflowRunId = useWorkflowRunIdOrThrow(); const workflowRun = useWorkflowRun({ workflowRunId }); const step = workflowRun?.output?.flow.steps.find( @@ -48,18 +54,27 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { return ( - ({ - id, - label: name, - value: context, - }))} - Icon={IconBrackets} - emptyElementsText="" - depth={0} - keyPath="" - shouldHighlightNode={(keyPath) => variablesUsedInStep.has(keyPath)} - /> + variablesUsedInStep.has(keyPath), + }} + > + ({ + id, + label: name, + value: context, + }))} + Icon={IconBrackets} + depth={0} + keyPath="" + emptyElementsText="" + /> + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx index d8c9062cf..c547b9f5f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx @@ -1,8 +1,9 @@ -import { JsonTree } from '@/workflow/components/json-visualizer/components/JsonTree'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import styled from '@emotion/styled'; +import { useLingui } from '@lingui/react/macro'; import { isDefined } from 'twenty-shared'; +import { JsonTree } from 'twenty-ui'; const StyledContainer = styled.div` display: grid; @@ -15,6 +16,8 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => { const workflowRunId = useWorkflowRunIdOrThrow(); const workflowRun = useWorkflowRun({ workflowRunId }); + const { t } = useLingui(); + if (!isDefined(workflowRun?.output?.stepsOutput)) { return null; } @@ -23,7 +26,13 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => { return ( - + ); }; diff --git a/packages/twenty-ui/src/index.ts b/packages/twenty-ui/src/index.ts index bd63145e4..561297ab1 100644 --- a/packages/twenty-ui/src/index.ts +++ b/packages/twenty-ui/src/index.ts @@ -3,6 +3,7 @@ export * from './components'; export * from './display'; export * from './feedback'; export * from './input'; +export * from './json-visualizer'; export * from './layout'; export * from './navigation'; export * from './testing'; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/__stories__/JsonTree.stories.tsx b/packages/twenty-ui/src/json-visualizer/__stories__/JsonTree.stories.tsx similarity index 97% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/__stories__/JsonTree.stories.tsx rename to packages/twenty-ui/src/json-visualizer/__stories__/JsonTree.stories.tsx index 96b553db1..198b1d207 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/__stories__/JsonTree.stories.tsx +++ b/packages/twenty-ui/src/json-visualizer/__stories__/JsonTree.stories.tsx @@ -1,4 +1,3 @@ -import { JsonTree } from '@/workflow/components/json-visualizer/components/JsonTree'; import { Meta, StoryObj } from '@storybook/react'; import { expect, @@ -6,14 +5,18 @@ import { waitForElementToBeRemoved, within, } from '@storybook/test'; -import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; +import { JsonTree } from '@ui/json-visualizer/components/JsonTree'; const meta: Meta = { - title: 'Modules/Workflow/JsonVisualizer/JsonTree', + title: 'UI/JsonVisualizer/JsonTree', component: JsonTree, - args: {}, + args: { + emptyArrayLabel: 'Empty Array', + emptyObjectLabel: 'Empty Object', + arrowButtonCollapsedLabel: 'Expand', + arrowButtonExpandedLabel: 'Collapse', + }, argTypes: {}, - decorators: [I18nFrontDecorator], }; export default meta; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonArrayNode.tsx similarity index 57% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx rename to packages/twenty-ui/src/json-visualizer/components/JsonArrayNode.tsx index 9ef496bc3..d17da3ab6 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonArrayNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonArrayNode.tsx @@ -1,6 +1,6 @@ -import { JsonNestedNode } from '@/workflow/components/json-visualizer/components/JsonNestedNode'; -import { useLingui } from '@lingui/react/macro'; -import { IconBrackets } from 'twenty-ui'; +import { IconBrackets } from '@ui/display'; +import { JsonNestedNode } from '@ui/json-visualizer/components/JsonNestedNode'; +import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow'; import { JsonArray } from 'type-fest'; export const JsonArrayNode = ({ @@ -8,15 +8,13 @@ export const JsonArrayNode = ({ value, depth, keyPath, - shouldHighlightNode, }: { label?: string; value: JsonArray; depth: number; keyPath: string; - shouldHighlightNode?: (keyPath: string) => boolean; }) => { - const { t } = useLingui(); + const { emptyArrayLabel } = useJsonTreeContextOrThrow(); return ( ); }; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNestedNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx similarity index 80% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNestedNode.tsx rename to packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx index 2ffda032b..29c08d3fa 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNestedNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx @@ -1,12 +1,12 @@ -import { JsonArrow } from '@/workflow/components/json-visualizer/components/internal/JsonArrow'; -import { JsonList } from '@/workflow/components/json-visualizer/components/internal/JsonList'; -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 { IconComponent } from '@ui/display'; +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 { useState } from 'react'; import { isDefined } from 'twenty-shared'; -import { IconComponent } from 'twenty-ui'; import { JsonValue } from 'type-fest'; const StyledContainer = styled.li` @@ -37,7 +37,6 @@ export const JsonNestedNode = ({ emptyElementsText, depth, keyPath, - shouldHighlightNode, }: { label?: string; Icon: IconComponent; @@ -46,7 +45,6 @@ export const JsonNestedNode = ({ emptyElementsText: string; depth: number; keyPath: string; - shouldHighlightNode?: (keyPath: string) => boolean; }) => { const hideRoot = !isDefined(label); @@ -69,7 +67,6 @@ export const JsonNestedNode = ({ value={value} depth={depth + 1} keyPath={nextKeyPath} - shouldHighlightNode={shouldHighlightNode} /> ); }) diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonNode.tsx similarity index 72% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNode.tsx rename to packages/twenty-ui/src/json-visualizer/components/JsonNode.tsx index e326bf4fc..1fae1916b 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonNode.tsx @@ -1,14 +1,15 @@ -import { JsonArrayNode } from '@/workflow/components/json-visualizer/components/JsonArrayNode'; -import { JsonObjectNode } from '@/workflow/components/json-visualizer/components/JsonObjectNode'; -import { JsonValueNode } from '@/workflow/components/json-visualizer/components/JsonValueNode'; -import { isArray } from '@/workflow/components/json-visualizer/utils/isArray'; import { isBoolean, isNull, isNumber, isString } from '@sniptt/guards'; import { IconCheckbox, IconCircleOff, IconNumber9, IconTypography, -} from 'twenty-ui'; +} from '@ui/display'; +import { JsonArrayNode } from '@ui/json-visualizer/components/JsonArrayNode'; +import { JsonObjectNode } from '@ui/json-visualizer/components/JsonObjectNode'; +import { JsonValueNode } from '@ui/json-visualizer/components/JsonValueNode'; +import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow'; +import { isArray } from '@ui/json-visualizer/utils/isArray'; import { JsonValue } from 'type-fest'; export const JsonNode = ({ @@ -16,14 +17,14 @@ export const JsonNode = ({ value, depth, keyPath, - shouldHighlightNode, }: { label?: string; value: JsonValue; depth: number; keyPath: string; - shouldHighlightNode?: (keyPath: string) => boolean; }) => { + const { shouldHighlightNode } = useJsonTreeContextOrThrow(); + const isHighlighted = shouldHighlightNode?.(keyPath) ?? false; if (isNull(value)) { @@ -77,7 +78,6 @@ export const JsonNode = ({ value={value} depth={depth} keyPath={keyPath} - shouldHighlightNode={shouldHighlightNode} /> ); } @@ -88,7 +88,6 @@ export const JsonNode = ({ value={value} depth={depth} keyPath={keyPath} - shouldHighlightNode={shouldHighlightNode} /> ); }; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonObjectNode.tsx similarity index 57% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx rename to packages/twenty-ui/src/json-visualizer/components/JsonObjectNode.tsx index 57bea7d37..e3f32fd34 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonObjectNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonObjectNode.tsx @@ -1,6 +1,6 @@ -import { JsonNestedNode } from '@/workflow/components/json-visualizer/components/JsonNestedNode'; -import { useLingui } from '@lingui/react/macro'; -import { IconCube } from 'twenty-ui'; +import { IconCube } from '@ui/display'; +import { JsonNestedNode } from '@ui/json-visualizer/components/JsonNestedNode'; +import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow'; import { JsonObject } from 'type-fest'; export const JsonObjectNode = ({ @@ -8,15 +8,13 @@ export const JsonObjectNode = ({ value, depth, keyPath, - shouldHighlightNode, }: { label?: string; value: JsonObject; depth: number; keyPath: string; - shouldHighlightNode?: (keyPath: string) => boolean; }) => { - const { t } = useLingui(); + const { emptyObjectLabel } = useJsonTreeContextOrThrow(); return ( ); }; diff --git a/packages/twenty-ui/src/json-visualizer/components/JsonTree.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonTree.tsx new file mode 100644 index 000000000..ef92c44a6 --- /dev/null +++ b/packages/twenty-ui/src/json-visualizer/components/JsonTree.tsx @@ -0,0 +1,36 @@ +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 { JsonValue } from 'type-fest'; + +export const JsonTree = ({ + value, + shouldHighlightNode, + emptyArrayLabel, + emptyObjectLabel, + arrowButtonCollapsedLabel, + arrowButtonExpandedLabel, +}: { + value: JsonValue; + shouldHighlightNode?: (keyPath: string) => boolean; + emptyArrayLabel: string; + emptyObjectLabel: string; + arrowButtonCollapsedLabel: string; + arrowButtonExpandedLabel: string; +}) => { + return ( + + + + + + ); +}; diff --git a/packages/twenty-ui/src/json-visualizer/components/JsonTreeContextProvider.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonTreeContextProvider.tsx new file mode 100644 index 000000000..6269e7d26 --- /dev/null +++ b/packages/twenty-ui/src/json-visualizer/components/JsonTreeContextProvider.tsx @@ -0,0 +1,18 @@ +import { + JsonTreeContext, + JsonTreeContextType, +} from '@ui/json-visualizer/contexts/JsonTreeContext'; + +export const JsonTreeContextProvider = ({ + value, + children, +}: { + value: JsonTreeContextType; + children: React.ReactNode; +}) => { + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonValueNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonValueNode.tsx similarity index 67% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonValueNode.tsx rename to packages/twenty-ui/src/json-visualizer/components/JsonValueNode.tsx index 10d5cb927..1fe661185 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/JsonValueNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonValueNode.tsx @@ -1,8 +1,8 @@ -import { JsonListItem } from '@/workflow/components/json-visualizer/components/internal/JsonListItem'; -import { JsonNodeLabel } from '@/workflow/components/json-visualizer/components/internal/JsonNodeLabel'; -import { JsonNodeValue } from '@/workflow/components/json-visualizer/components/internal/JsonNodeValue'; import styled from '@emotion/styled'; -import { IconComponent } from 'twenty-ui'; +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'; const StyledListItem = styled(JsonListItem)` column-gap: ${({ theme }) => theme.spacing(2)}; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/internal/JsonArrow.tsx b/packages/twenty-ui/src/json-visualizer/components/internal/JsonArrow.tsx similarity index 71% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/internal/JsonArrow.tsx rename to packages/twenty-ui/src/json-visualizer/components/internal/JsonArrow.tsx index 60ddf0e13..6b4bf720b 100644 --- a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/internal/JsonArrow.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/internal/JsonArrow.tsx @@ -1,8 +1,9 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useLingui } from '@lingui/react/macro'; +import { VisibilityHidden } from '@ui/accessibility'; +import { IconChevronDown } from '@ui/display'; +import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow'; import { motion } from 'framer-motion'; -import { IconChevronDown, VisibilityHidden } from 'twenty-ui'; const StyledButton = styled(motion.button)` align-items: center; @@ -29,13 +30,16 @@ export const JsonArrow = ({ isOpen: boolean; onClick: () => void; }) => { - const { t } = useLingui(); - const theme = useTheme(); + const { arrowButtonCollapsedLabel, arrowButtonExpandedLabel } = + useJsonTreeContextOrThrow(); + return ( - {isOpen ? t`Collapse` : t`Expand`} + + {isOpen ? arrowButtonExpandedLabel : arrowButtonCollapsedLabel} + ` align-items: center; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/components/internal/JsonNodeValue.tsx b/packages/twenty-ui/src/json-visualizer/components/internal/JsonNodeValue.tsx similarity index 100% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/components/internal/JsonNodeValue.tsx rename to packages/twenty-ui/src/json-visualizer/components/internal/JsonNodeValue.tsx diff --git a/packages/twenty-ui/src/json-visualizer/contexts/JsonTreeContext.tsx b/packages/twenty-ui/src/json-visualizer/contexts/JsonTreeContext.tsx new file mode 100644 index 000000000..64bfc49e3 --- /dev/null +++ b/packages/twenty-ui/src/json-visualizer/contexts/JsonTreeContext.tsx @@ -0,0 +1,13 @@ +import { createContext } from 'react'; + +export type JsonTreeContextType = { + shouldHighlightNode?: (keyPath: string) => boolean; + emptyArrayLabel: string; + emptyObjectLabel: string; + arrowButtonCollapsedLabel: string; + arrowButtonExpandedLabel: string; +}; + +export const JsonTreeContext = createContext( + undefined, +); diff --git a/packages/twenty-ui/src/json-visualizer/hooks/useJsonTreeContextOrThrow.tsx b/packages/twenty-ui/src/json-visualizer/hooks/useJsonTreeContextOrThrow.tsx new file mode 100644 index 000000000..0bb0d0234 --- /dev/null +++ b/packages/twenty-ui/src/json-visualizer/hooks/useJsonTreeContextOrThrow.tsx @@ -0,0 +1,15 @@ +import { JsonTreeContext } from '@ui/json-visualizer/contexts/JsonTreeContext'; +import { useContext } from 'react'; +import { isDefined } from 'twenty-shared'; + +export const useJsonTreeContextOrThrow = () => { + const value = useContext(JsonTreeContext); + + if (!isDefined(value)) { + throw new Error( + 'useJsonTreeContextOrThrow must be used within a JsonTreeContextProvider', + ); + } + + return value; +}; diff --git a/packages/twenty-ui/src/json-visualizer/index.ts b/packages/twenty-ui/src/json-visualizer/index.ts new file mode 100644 index 000000000..649bc8032 --- /dev/null +++ b/packages/twenty-ui/src/json-visualizer/index.ts @@ -0,0 +1,10 @@ +export * from './components/JsonArrayNode'; +export * from './components/JsonNestedNode'; +export * from './components/JsonNode'; +export * from './components/JsonObjectNode'; +export * from './components/JsonTree'; +export * from './components/JsonTreeContextProvider'; +export * from './components/JsonValueNode'; +export * from './contexts/JsonTreeContext'; +export * from './hooks/useJsonTreeContextOrThrow'; +export * from './utils/isArray'; diff --git a/packages/twenty-front/src/modules/workflow/components/json-visualizer/utils/isArray.ts b/packages/twenty-ui/src/json-visualizer/utils/isArray.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/components/json-visualizer/utils/isArray.ts rename to packages/twenty-ui/src/json-visualizer/utils/isArray.ts