From b6202fe98cb0103a96effce00a8218ca69deea4e Mon Sep 17 00:00:00 2001 From: Hansol Yang Date: Mon, 12 Aug 2024 19:18:05 +0900 Subject: [PATCH] Issue6335: RecordInlineCell tree refactor with RecordInlineCellContext (#6537) Fixes [#6335](https://github.com/twentyhq/twenty/issues/6335) This pull request is for issue [#6335](https://github.com/twentyhq/twenty/issues/6335): Refactor RecordInlineCell tree with a Context to avoid props drilling. For the refactoring, this PR made changes as below: - Created new script RecordInlineCellContext.tsx: Defining a context to pass in useContext() - Updated RecordInlineCell.tsx: Passing the necessary props as context values, wrapping with RecordInlineCellContext.Provider - Updated RecordInlineCellContainer.tsx: Passing the props to RecordInlineContainer as RecordInlineCellContext - Updated RecordInlineCellDisplayMode.tsx: retrieves values from useRecordInlineCellContext instead of directly assigning them - RecordInlineCellValue.tsx: Removed values passed through as they are now retrieved through useRecordInlineCellContext + Removed the null check for RecordInlineCellContextProps. Using RecordInlineCellContext, I believe the context goes to the top of the hierarchy and passed to the required layers without going through several layers. However, please let me know if I understood the issue incorrectly or it is not solved properly. Thank you in advance for your review! --------- Co-authored-by: Lucas Bordeau --- .../components/ActivityTargetsInlineCell.tsx | 53 +++++++----- .../components/RecordInlineCell.tsx | 83 ++++++++++--------- .../components/RecordInlineCellContainer.tsx | 40 ++------- .../components/RecordInlineCellContext.tsx | 47 +++++++++++ .../RecordInlineCellDisplayMode.tsx | 45 +++++----- .../components/RecordInlineCellValue.tsx | 60 +++----------- 6 files changed, 160 insertions(+), 168 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContext.tsx diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx index b275231ca9..60494d98bd 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx @@ -14,6 +14,7 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider'; import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope'; import { RecordInlineCellContainer } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer'; +import { RecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; @@ -65,30 +66,36 @@ export const ActivityTargetsInlineCell = ({ {ActivityTargetsContextProvider && ( - + ), + label: 'Relations', + displayModeContent: ( + + ), }} - IconLabel={showLabel ? IconArrowUpRight : undefined} - showLabel={showLabel} - readonly={readonly} - labelWidth={fieldDefinition?.labelWidth} - editModeContent={ - - } - label="Relations" - displayModeContent={ - - } - /> + > + + )} diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx index dff1504c0d..e2c8b2bcfa 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx @@ -16,6 +16,10 @@ import { useInlineCell } from '../hooks/useInlineCell'; import { useIsFieldReadOnly } from '@/object-record/record-field/hooks/useIsFieldReadOnly'; import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId'; import { RecordInlineCellContainer } from './RecordInlineCellContainer'; +import { + RecordInlineCellContext, + RecordInlineCellContextProps, +} from './RecordInlineCellContext'; type RecordInlineCellProps = { readonly?: boolean; @@ -23,7 +27,6 @@ type RecordInlineCellProps = { isCentered?: boolean; }; -// TODO: refactor props drilling with a RecordInlineCellContext export const RecordInlineCell = ({ readonly, loading, @@ -75,48 +78,46 @@ export const RecordInlineCell = ({ const { getIcon } = useIcons(); + const RecordInlineCellContextValue: RecordInlineCellContextProps = { + readonly: cellIsReadOnly, + buttonIcon: buttonIcon, + customEditHotkeyScope: isFieldRelation(fieldDefinition) + ? { scope: RelationPickerHotkeyScope.RelationPicker } + : undefined, + IconLabel: fieldDefinition.iconName + ? getIcon(fieldDefinition.iconName) + : undefined, + label: fieldDefinition.label, + labelWidth: fieldDefinition.labelWidth, + showLabel: fieldDefinition.showLabel, + isCentered: isCentered, + editModeContent: ( + + ), + displayModeContent: , + isDisplayModeFixHeight: undefined, + editModeContentOnly: isFieldInputOnly, + loading: loading, + }; + return ( - - } - displayModeContent={} - isDisplayModeFixHeight - editModeContentOnly={isFieldInputOnly} - loading={loading} - /> + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx index 579acab672..4c12e25417 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx @@ -10,6 +10,8 @@ import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInput import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useRecordInlineCellContext } from './RecordInlineCellContext'; + const StyledIconContainer = styled.div` align-items: center; color: ${({ theme }) => theme.font.color.tertiary}; @@ -78,23 +80,10 @@ export type RecordInlineCellContainerProps = { isCentered?: boolean; }; -// TODO: refactor props drilling with a RecordInlineCellContext -export const RecordInlineCellContainer = ({ - readonly, - IconLabel, - label, - labelWidth, - showLabel, - buttonIcon, - editModeContent, - displayModeContent, - customEditHotkeyScope, - editModeContentOnly, - isDisplayModeFixHeight, - disableHoverEffect, - loading = false, - isCentered, -}: RecordInlineCellContainerProps) => { +export const RecordInlineCellContainer = () => { + const { readonly, IconLabel, label, labelWidth, showLabel } = + useRecordInlineCellContext(); + const { recordId, fieldDefinition } = useContext(FieldContext); const { setIsFocused } = useFieldFocus(); @@ -149,22 +138,7 @@ export const RecordInlineCellContainer = ({ )} - + ); diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContext.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContext.tsx new file mode 100644 index 0000000000..9f227be323 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContext.tsx @@ -0,0 +1,47 @@ +import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { createContext, ReactElement, useContext } from 'react'; +import { IconComponent } from 'twenty-ui'; + +export type RecordInlineCellContextProps = { + readonly?: boolean; + IconLabel?: IconComponent; + label?: string; + labelWidth?: number; + showLabel?: boolean; + buttonIcon?: IconComponent; + editModeContent?: ReactElement; + editModeContentOnly?: boolean; + displayModeContent?: ReactElement; + customEditHotkeyScope?: HotkeyScope; + isDisplayModeFixHeight?: boolean; + disableHoverEffect?: boolean; + loading?: boolean; + isCentered?: boolean; +}; + +const defaultRecordInlineCellContextProp: RecordInlineCellContextProps = { + readonly: false, + IconLabel: undefined, + label: '', + labelWidth: 0, + showLabel: false, + buttonIcon: undefined, + editModeContent: undefined, + editModeContentOnly: false, + displayModeContent: undefined, + customEditHotkeyScope: undefined, + isDisplayModeFixHeight: false, + disableHoverEffect: false, + loading: false, + isCentered: false, +}; + +export const RecordInlineCellContext = + createContext( + defaultRecordInlineCellContextProp, + ); + +export const useRecordInlineCellContext = (): RecordInlineCellContextProps => { + const context = useContext(RecordInlineCellContext); + return context; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx index eacdf2dc4b..cf57e47ac0 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx @@ -4,14 +4,17 @@ import styled from '@emotion/styled'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty'; import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly'; -import { RecordInlineCellContainerProps } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer'; +import { + RecordInlineCellContextProps, + useRecordInlineCellContext, +} from '@/object-record/record-inline-cell/components/RecordInlineCellContext'; import { RecordInlineCellButton } from '@/object-record/record-inline-cell/components/RecordInlineCellEditButton'; const StyledRecordInlineCellNormalModeOuterContainer = styled.div< Pick< - RecordInlineCellDisplayModeProps, - 'disableHoverEffect' | 'isDisplayModeFixHeight' | 'isHovered' - > + RecordInlineCellContextProps, + 'isDisplayModeFixHeight' | 'disableHoverEffect' + > & { isHovered?: boolean } >` align-items: center; border-radius: ${({ theme }) => theme.border.radius.sm}; @@ -53,23 +56,19 @@ const StyledEmptyField = styled.div` color: ${({ theme }) => theme.font.color.light}; `; -type RecordInlineCellDisplayModeProps = { - disableHoverEffect?: boolean; - isDisplayModeFixHeight?: boolean; - isHovered?: boolean; - emptyPlaceholder?: string; -} & Pick; - export const RecordInlineCellDisplayMode = ({ children, - disableHoverEffect, - isDisplayModeFixHeight, - emptyPlaceholder = 'Empty', - isHovered, - buttonIcon, - editModeContentOnly, -}: React.PropsWithChildren) => { +}: React.PropsWithChildren) => { const { isFocused } = useFieldFocus(); + + const { + editModeContentOnly, + + showLabel, + label, + buttonIcon, + } = useRecordInlineCellContext(); + const isDisplayModeContentEmpty = useIsFieldEmpty(); const showEditButton = buttonIcon && @@ -81,17 +80,15 @@ export const RecordInlineCellDisplayMode = ({ const shouldDisplayEditModeOnFocus = isFocused && isFieldInputOnly; + const emptyPlaceHolder = showLabel ? 'Empty' : label; + return ( <> - + {(isDisplayModeContentEmpty && !shouldDisplayEditModeOnFocus) || !children ? ( - {emptyPlaceholder} + {emptyPlaceHolder} ) : ( children )} diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx index 6ee1c3b557..738890d52e 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx @@ -1,8 +1,7 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; -import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; -import { RecordInlineCellContainerProps } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer'; +import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext'; import { RecordInlineCellDisplayMode } from '@/object-record/record-inline-cell/components/RecordInlineCellDisplayMode'; import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode'; import { RecordInlineCellSkeletonLoader } from '@/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader'; @@ -29,37 +28,16 @@ const StyledClickableContainer = styled.div<{ `}; `; -type RecordInlineCellValueProps = Pick< - RecordInlineCellContainerProps, - | 'displayModeContent' - | 'customEditHotkeyScope' - | 'editModeContent' - | 'editModeContentOnly' - | 'isDisplayModeFixHeight' - | 'disableHoverEffect' - | 'readonly' - | 'buttonIcon' - | 'loading' - | 'showLabel' - | 'label' - | 'isCentered' ->; - -export const RecordInlineCellValue = ({ - displayModeContent, - customEditHotkeyScope, - disableHoverEffect, - editModeContent, - editModeContentOnly, - isDisplayModeFixHeight, - readonly, - buttonIcon, - loading, - showLabel, - label, - isCentered, -}: RecordInlineCellValueProps) => { - const { isFocused } = useFieldFocus(); +export const RecordInlineCellValue = () => { + const { + displayModeContent, + customEditHotkeyScope, + editModeContent, + editModeContentOnly, + readonly, + loading, + isCentered, + } = useRecordInlineCellContext(); const { isInlineCellInEditMode, openInlineCell } = useInlineCell(); @@ -80,12 +58,7 @@ export const RecordInlineCellValue = ({ )} {editModeContentOnly ? ( - + {editModeContent} @@ -95,14 +68,7 @@ export const RecordInlineCellValue = ({ onClick={handleDisplayModeClick} isCentered={isCentered} > - + {displayModeContent}