Replace hotkey scopes by focus stack (Part 4 - Inputs) (#12933)
# Replace hotkey scopes by focus stack (Part 4 - Inputs) This PR is the 4th part of a refactoring aiming to deprecate the hotkey scopes api in favor of the new focus stack api which is more robust. Part 1: https://github.com/twentyhq/twenty/pull/12673 Part 2: https://github.com/twentyhq/twenty/pull/12798 Part 3: https://github.com/twentyhq/twenty/pull/12910 In this part, I refactored all inputs in the app so that each input has a unique id which can be used to track the focused element.
This commit is contained in:
@ -64,15 +64,15 @@ const TextInput: React.FC<TextInputProps> = ({
|
|||||||
placeholder,
|
placeholder,
|
||||||
icon,
|
icon,
|
||||||
}) => {
|
}) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer fullWidth={fullWidth}>
|
<StyledContainer fullWidth={fullWidth}>
|
||||||
{label && <StyledLabel htmlFor={inputId}>{label}</StyledLabel>}
|
{label && <StyledLabel htmlFor={instanceId}>{label}</StyledLabel>}
|
||||||
<StyledInputContainer>
|
<StyledInputContainer>
|
||||||
{icon && <StyledIcon>{icon}</StyledIcon>}
|
{icon && <StyledIcon>{icon}</StyledIcon>}
|
||||||
<StyledInput
|
<StyledInput
|
||||||
id={inputId}
|
id={instanceId}
|
||||||
type="text"
|
type="text"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { Chip, ChipAccent, ChipSize, ChipVariant } from 'twenty-ui/components';
|
import { Chip, ChipAccent, ChipSize, ChipVariant } from 'twenty-ui/components';
|
||||||
import { IconCalendarEvent } from 'twenty-ui/display';
|
import { IconCalendarEvent } from 'twenty-ui/display';
|
||||||
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
||||||
@ -20,6 +20,8 @@ type CalendarEventDetailsProps = {
|
|||||||
calendarEvent: CalendarEvent;
|
calendarEvent: CalendarEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const INPUT_ID_PREFIX = 'calendar-event-details';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
background: ${({ theme }) => theme.background.secondary};
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -111,10 +113,14 @@ export const CalendarEventDetails = ({
|
|||||||
>
|
>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(calendarEvent.id, fieldName),
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
|
recordId: calendarEvent.id,
|
||||||
|
fieldName,
|
||||||
|
prefix: INPUT_ID_PREFIX,
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordInlineCell readonly />
|
<RecordInlineCell instanceIdPrefix={INPUT_ID_PREFIX} />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
</StyledPropertyBox>
|
</StyledPropertyBox>
|
||||||
|
|||||||
@ -34,8 +34,7 @@ import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecor
|
|||||||
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
|
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
|
||||||
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
|
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
|
||||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||||
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { getRecordTitleCellId } from '@/object-record/record-title-cell/utils/getRecordTitleCellId';
|
|
||||||
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
|
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||||
@ -364,11 +363,11 @@ export const ActivityRichTextEditor = ({
|
|||||||
objectRecordId: activityId,
|
objectRecordId: activityId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const recordTitleCellId = getRecordTitleCellId(
|
const recordTitleCellId = getRecordFieldInputInstanceId({
|
||||||
activityId,
|
recordId: activityId,
|
||||||
labelIdentifierFieldMetadataItem?.id,
|
fieldName: labelIdentifierFieldMetadataItem?.id,
|
||||||
RecordTitleCellContainerType.ShowPage,
|
prefix: 'activity-rich-text-editor',
|
||||||
);
|
});
|
||||||
|
|
||||||
const handleBlockEditorFocus = useRecoilCallback(
|
const handleBlockEditorFocus = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
|
|||||||
@ -165,6 +165,7 @@ export const AttachmentRow = ({
|
|||||||
<AttachmentIcon attachmentType={attachment.type} />
|
<AttachmentIcon attachmentType={attachment.type} />
|
||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={`attachment-${attachment.id}-name`}
|
||||||
value={attachmentFileName}
|
value={attachmentFileName}
|
||||||
onChange={handleOnChange}
|
onChange={handleOnChange}
|
||||||
onBlur={handleOnBlur}
|
onBlur={handleOnBlur}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { Controller, useFormContext } from 'react-hook-form';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm';
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledFullWidthMotionDiv = styled(motion.div)`
|
const StyledFullWidthMotionDiv = styled(motion.div)`
|
||||||
@ -41,6 +41,7 @@ export const SignInUpEmailField = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<StyledInputContainer>
|
<StyledInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sign-in-up-email"
|
||||||
autoFocus
|
autoFocus
|
||||||
value={value}
|
value={value}
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
|
|||||||
@ -46,6 +46,7 @@ export const SignInUpPasswordField = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<StyledInputContainer>
|
<StyledInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sign-in-up-password"
|
||||||
autoFocus
|
autoFocus
|
||||||
value={value}
|
value={value}
|
||||||
type="password"
|
type="password"
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export const ObjectFilterDropdownNumberInput = () => {
|
|||||||
return (
|
return (
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<DropdownMenuInput
|
<DropdownMenuInput
|
||||||
|
instanceId="object-filter-dropdown-number-input"
|
||||||
ref={handleInputRef}
|
ref={handleInputRef}
|
||||||
value={objectFilterDropdownFilterValue}
|
value={objectFilterDropdownFilterValue}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export const ObjectFilterDropdownTextInput = () => {
|
|||||||
return (
|
return (
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<DropdownMenuInput
|
<DropdownMenuInput
|
||||||
|
instanceId="object-filter-dropdown-text-input"
|
||||||
ref={handleInputRef}
|
ref={handleInputRef}
|
||||||
value={objectFilterDropdownFilterValue}
|
value={objectFilterDropdownFilterValue}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
import { RecordBoardCardBodyContainer } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBodyContainer';
|
import { RecordBoardCardBodyContainer } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBodyContainer';
|
||||||
import { StopPropagationContainer } from '@/object-record/record-board/record-board-card/components/StopPropagationContainer';
|
import { StopPropagationContainer } from '@/object-record/record-board/record-board-card/components/StopPropagationContainer';
|
||||||
|
import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix';
|
||||||
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||||
import { RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition';
|
import { RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition';
|
||||||
import {
|
import {
|
||||||
@ -13,7 +14,7 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
|
|||||||
import { getFieldButtonIcon } from '@/object-record/record-field/utils/getFieldButtonIcon';
|
import { getFieldButtonIcon } from '@/object-record/record-field/utils/getFieldButtonIcon';
|
||||||
import { isFieldValueReadOnly } from '@/object-record/record-field/utils/isFieldValueReadOnly';
|
import { isFieldValueReadOnly } from '@/object-record/record-field/utils/isFieldValueReadOnly';
|
||||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
export const RecordBoardCardBody = ({
|
export const RecordBoardCardBody = ({
|
||||||
@ -73,14 +74,16 @@ export const RecordBoardCardBody = ({
|
|||||||
>
|
>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
'record-board-card',
|
prefix: RECORD_BOARD_CARD_INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordInlineCell />
|
<RecordInlineCell
|
||||||
|
instanceIdPrefix={RECORD_BOARD_CARD_INPUT_ID_PREFIX}
|
||||||
|
/>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
</StopPropagationContainer>
|
</StopPropagationContainer>
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const RECORD_BOARD_CARD_INPUT_ID_PREFIX = 'record-board-card';
|
||||||
@ -29,7 +29,7 @@ export const FormBooleanFieldInput = ({
|
|||||||
readonly,
|
readonly,
|
||||||
VariablePicker,
|
VariablePicker,
|
||||||
}: FormBooleanFieldInputProps) => {
|
}: FormBooleanFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const [draftValue, setDraftValue] = useState<
|
const [draftValue, setDraftValue] = useState<
|
||||||
| {
|
| {
|
||||||
@ -105,7 +105,7 @@ export const FormBooleanFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly ? (
|
{VariablePicker && !readonly ? (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export const FormDateTimeFieldInput = ({
|
|||||||
isDateTimeInput: !dateOnly,
|
isDateTimeInput: !dateOnly,
|
||||||
});
|
});
|
||||||
|
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const [draftValue, setDraftValue] = useState<DraftValue>(
|
const [draftValue, setDraftValue] = useState<DraftValue>(
|
||||||
isStandaloneVariableString(defaultValue)
|
isStandaloneVariableString(defaultValue)
|
||||||
@ -340,7 +340,7 @@ export const FormDateTimeFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly ? (
|
{VariablePicker && !readonly ? (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -82,7 +82,7 @@ export const FormMultiSelectFieldInput = ({
|
|||||||
placeholder,
|
placeholder,
|
||||||
testId,
|
testId,
|
||||||
}: FormMultiSelectFieldInputProps) => {
|
}: FormMultiSelectFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const hotkeyScope =
|
const hotkeyScope =
|
||||||
@ -268,7 +268,7 @@ export const FormMultiSelectFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly && (
|
{VariablePicker && !readonly && (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export const FormNumberFieldInput = ({
|
|||||||
readonly,
|
readonly,
|
||||||
error: errorFromProps,
|
error: errorFromProps,
|
||||||
}: FormNumberFieldInputProps) => {
|
}: FormNumberFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
@ -117,7 +117,7 @@ export const FormNumberFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FormFieldInputContainer>
|
<FormFieldInputContainer>
|
||||||
{label ? <InputLabel htmlFor={inputId}>{label}</InputLabel> : null}
|
{label ? <InputLabel htmlFor={instanceId}>{label}</InputLabel> : null}
|
||||||
|
|
||||||
<FormFieldInputRowContainer>
|
<FormFieldInputRowContainer>
|
||||||
<FormFieldInputInnerContainer
|
<FormFieldInputInnerContainer
|
||||||
@ -126,7 +126,7 @@ export const FormNumberFieldInput = ({
|
|||||||
>
|
>
|
||||||
{draftValue.type === 'static' ? (
|
{draftValue.type === 'static' ? (
|
||||||
<StyledInput
|
<StyledInput
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
placeholder={
|
placeholder={
|
||||||
isDefined(placeholder) && !isEmpty(placeholder)
|
isDefined(placeholder) && !isEmpty(placeholder)
|
||||||
? placeholder
|
? placeholder
|
||||||
@ -148,7 +148,7 @@ export const FormNumberFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly ? (
|
{VariablePicker && !readonly ? (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export const FormRawJsonFieldInput = ({
|
|||||||
readonly,
|
readonly,
|
||||||
VariablePicker,
|
VariablePicker,
|
||||||
}: FormRawJsonFieldInputProps) => {
|
}: FormRawJsonFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const editor = useTextVariableEditor({
|
const editor = useTextVariableEditor({
|
||||||
placeholder: placeholder ?? 'Enter a JSON object',
|
placeholder: placeholder ?? 'Enter a JSON object',
|
||||||
@ -80,7 +80,7 @@ export const FormRawJsonFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly && (
|
{VariablePicker && !readonly && (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
multiline
|
multiline
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -6,16 +6,16 @@ import { VariablePickerComponent } from '@/object-record/record-field/form-types
|
|||||||
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
||||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import { useId, useState } from 'react';
|
import { useId, useState } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { SelectOption } from 'twenty-ui/input';
|
|
||||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { IconCircleOff } from 'twenty-ui/display';
|
import { IconCircleOff } from 'twenty-ui/display';
|
||||||
|
import { SelectOption } from 'twenty-ui/input';
|
||||||
|
|
||||||
type FormSelectFieldInputProps = {
|
type FormSelectFieldInputProps = {
|
||||||
label?: string;
|
label?: string;
|
||||||
@ -36,7 +36,7 @@ export const FormSelectFieldInput = ({
|
|||||||
}: FormSelectFieldInputProps) => {
|
}: FormSelectFieldInputProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const hotkeyScope = InlineCellHotkeyScope.InlineCell;
|
const hotkeyScope = InlineCellHotkeyScope.InlineCell;
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ export const FormSelectFieldInput = ({
|
|||||||
<FormFieldInputRowContainer>
|
<FormFieldInputRowContainer>
|
||||||
{draftValue.type === 'static' ? (
|
{draftValue.type === 'static' ? (
|
||||||
<Select
|
<Select
|
||||||
dropdownId={`${inputId}-select-display`}
|
dropdownId={`${instanceId}-select-display`}
|
||||||
options={options}
|
options={options}
|
||||||
value={selectedOption?.value}
|
value={selectedOption?.value}
|
||||||
onChange={onSelect}
|
onChange={onSelect}
|
||||||
@ -160,7 +160,7 @@ export const FormSelectFieldInput = ({
|
|||||||
|
|
||||||
{isDefined(VariablePicker) && !readonly && (
|
{isDefined(VariablePicker) && !readonly && (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -204,7 +204,7 @@ export const FormSingleRecordPicker = ({
|
|||||||
)}
|
)}
|
||||||
{isDefined(VariablePicker) && !disabled && (
|
{isDefined(VariablePicker) && !disabled && (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={variablesDropdownId}
|
instanceId={variablesDropdownId}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
objectNameSingularToSelect={objectNameSingular}
|
objectNameSingularToSelect={objectNameSingular}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export const FormTextFieldInput = ({
|
|||||||
readonly,
|
readonly,
|
||||||
VariablePicker,
|
VariablePicker,
|
||||||
}: FormTextFieldInputProps) => {
|
}: FormTextFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const editor = useTextVariableEditor({
|
const editor = useTextVariableEditor({
|
||||||
placeholder: placeholder ?? 'Enter text',
|
placeholder: placeholder ?? 'Enter text',
|
||||||
@ -84,7 +84,7 @@ export const FormTextFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly ? (
|
{VariablePicker && !readonly ? (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
multiline={multiline}
|
multiline={multiline}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export const FormUuidFieldInput = ({
|
|||||||
readonly,
|
readonly,
|
||||||
VariablePicker,
|
VariablePicker,
|
||||||
}: FormUuidFieldInputProps) => {
|
}: FormUuidFieldInputProps) => {
|
||||||
const inputId = useId();
|
const instanceId = useId();
|
||||||
|
|
||||||
const [draftValue, setDraftValue] = useState<
|
const [draftValue, setDraftValue] = useState<
|
||||||
| {
|
| {
|
||||||
@ -91,7 +91,7 @@ export const FormUuidFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FormFieldInputContainer>
|
<FormFieldInputContainer>
|
||||||
{label ? <InputLabel htmlFor={inputId}>{label}</InputLabel> : null}
|
{label ? <InputLabel htmlFor={instanceId}>{label}</InputLabel> : null}
|
||||||
|
|
||||||
<FormFieldInputRowContainer>
|
<FormFieldInputRowContainer>
|
||||||
<FormFieldInputInnerContainer
|
<FormFieldInputInnerContainer
|
||||||
@ -99,7 +99,7 @@ export const FormUuidFieldInput = ({
|
|||||||
>
|
>
|
||||||
{draftValue.type === 'static' ? (
|
{draftValue.type === 'static' ? (
|
||||||
<StyledInput
|
<StyledInput
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
placeholder={placeholder ?? 'Enter a UUID'}
|
placeholder={placeholder ?? 'Enter a UUID'}
|
||||||
value={draftValue.value}
|
value={draftValue.value}
|
||||||
copyButton={false}
|
copyButton={false}
|
||||||
@ -117,7 +117,7 @@ export const FormUuidFieldInput = ({
|
|||||||
|
|
||||||
{VariablePicker && !readonly ? (
|
{VariablePicker && !readonly ? (
|
||||||
<VariablePicker
|
<VariablePicker
|
||||||
inputId={inputId}
|
instanceId={instanceId}
|
||||||
onVariableSelect={handleVariableTagInsert}
|
onVariableSelect={handleVariableTagInsert}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export type VariablePickerComponent = React.FC<{
|
export type VariablePickerComponent = React.FC<{
|
||||||
inputId: string;
|
instanceId: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
multiline?: boolean;
|
multiline?: boolean;
|
||||||
onVariableSelect: (variableName: string) => void;
|
onVariableSelect: (variableName: string) => void;
|
||||||
|
|||||||
@ -15,11 +15,11 @@ import {
|
|||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects';
|
import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects';
|
||||||
import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject';
|
import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
@ -41,9 +41,11 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
({
|
({
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
recordId,
|
recordId,
|
||||||
|
prefix,
|
||||||
}: {
|
}: {
|
||||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||||
recordId: string;
|
recordId: string;
|
||||||
|
prefix?: string;
|
||||||
}) => {
|
}) => {
|
||||||
if (
|
if (
|
||||||
isFieldRelationFromManyObjects(fieldDefinition) &&
|
isFieldRelationFromManyObjects(fieldDefinition) &&
|
||||||
@ -75,9 +77,10 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openActivityTargetCellEditMode({
|
openActivityTargetCellEditMode({
|
||||||
recordPickerInstanceId: getFieldInputInstanceId({
|
recordPickerInstanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix,
|
||||||
}),
|
}),
|
||||||
activityTargetObjectRecords,
|
activityTargetObjectRecords,
|
||||||
});
|
});
|
||||||
@ -87,7 +90,8 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
if (isFieldRelationToOneObject(fieldDefinition)) {
|
if (isFieldRelationToOneObject(fieldDefinition)) {
|
||||||
openRelationToOneFieldInput({
|
openRelationToOneFieldInput({
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
recordId: recordId,
|
recordId,
|
||||||
|
prefix,
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -103,22 +107,25 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
objectNameSingular:
|
objectNameSingular:
|
||||||
fieldDefinition.metadata.relationObjectMetadataNameSingular,
|
fieldDefinition.metadata.relationObjectMetadataNameSingular,
|
||||||
recordId: recordId,
|
recordId,
|
||||||
|
prefix,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getFieldInputInstanceId({
|
focusId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix,
|
||||||
}),
|
}),
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.OPENED_FIELD_INPUT,
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
instanceId: getFieldInputInstanceId({
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
hotkeyScope: {
|
hotkeyScope: {
|
||||||
@ -142,14 +149,17 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
const closeFieldInput = ({
|
const closeFieldInput = ({
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
recordId,
|
recordId,
|
||||||
|
prefix,
|
||||||
}: {
|
}: {
|
||||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||||
recordId: string;
|
recordId: string;
|
||||||
|
prefix?: string;
|
||||||
}) => {
|
}) => {
|
||||||
removeFocusItemFromFocusStackById({
|
removeFocusItemFromFocusStackById({
|
||||||
focusId: getFieldInputInstanceId({
|
focusId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,11 +2,13 @@ import { useAddressField } from '@/object-record/record-field/meta-types/hooks/u
|
|||||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||||
import { AddressInput } from '@/ui/field/input/components/AddressInput';
|
import { AddressInput } from '@/ui/field/input/components/AddressInput';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
|
|
||||||
export type AddressFieldInputProps = {
|
export type AddressFieldInputProps = {
|
||||||
@ -70,8 +72,13 @@ export const AddressFieldInput = ({
|
|||||||
setDraftValue(convertToAddress(newAddress));
|
setDraftValue(convertToAddress(newAddress));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AddressInput
|
<AddressInput
|
||||||
|
instanceId={instanceId}
|
||||||
value={convertToAddress(draftValue)}
|
value={convertToAddress(draftValue)}
|
||||||
onClickOutside={handleClickOutside}
|
onClickOutside={handleClickOutside}
|
||||||
onEnter={handleEnter}
|
onEnter={handleEnter}
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import { CurrencyInput } from '@/ui/field/input/components/CurrencyInput';
|
|||||||
|
|
||||||
import { useCurrencyField } from '../../hooks/useCurrencyField';
|
import { useCurrencyField } from '../../hooks/useCurrencyField';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
type CurrencyFieldInputProps = {
|
type CurrencyFieldInputProps = {
|
||||||
@ -31,6 +33,10 @@ export const CurrencyFieldInput = ({
|
|||||||
const { draftValue, persistCurrencyField, setDraftValue, defaultValue } =
|
const { draftValue, persistCurrencyField, setDraftValue, defaultValue } =
|
||||||
useCurrencyField();
|
useCurrencyField();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const defaultCurrencyCodeWithoutSQLQuotes = (
|
const defaultCurrencyCodeWithoutSQLQuotes = (
|
||||||
defaultValue as FieldCurrencyValue
|
defaultValue as FieldCurrencyValue
|
||||||
).currencyCode.replace(/'/g, '') as CurrencyCode;
|
).currencyCode.replace(/'/g, '') as CurrencyCode;
|
||||||
@ -114,6 +120,7 @@ export const CurrencyFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CurrencyInput
|
<CurrencyInput
|
||||||
|
instanceId={instanceId}
|
||||||
value={draftValue?.amount?.toString() ?? ''}
|
value={draftValue?.amount?.toString() ?? ''}
|
||||||
currencyCode={currencyCode}
|
currencyCode={currencyCode}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { useDateField } from '@/object-record/record-field/meta-types/hooks/useDateField';
|
import { useDateField } from '@/object-record/record-field/meta-types/hooks/useDateField';
|
||||||
import { DateInput } from '@/ui/field/input/components/DateInput';
|
import { DateInput } from '@/ui/field/input/components/DateInput';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { Nullable } from 'twenty-ui/utilities';
|
import { Nullable } from 'twenty-ui/utilities';
|
||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
@ -26,6 +28,10 @@ export const DateFieldInput = ({
|
|||||||
}: DateFieldInputProps) => {
|
}: DateFieldInputProps) => {
|
||||||
const { fieldValue, setDraftValue } = useDateField();
|
const { fieldValue, setDraftValue } = useDateField();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
|
|
||||||
const persistDate = (newDate: Nullable<Date>) => {
|
const persistDate = (newDate: Nullable<Date>) => {
|
||||||
@ -73,6 +79,7 @@ export const DateFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DateInput
|
<DateInput
|
||||||
|
instanceId={instanceId}
|
||||||
onClickOutside={handleClickOutside}
|
onClickOutside={handleClickOutside}
|
||||||
onEnter={handleEnter}
|
onEnter={handleEnter}
|
||||||
onEscape={handleEscape}
|
onEscape={handleEscape}
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import { DateInput } from '@/ui/field/input/components/DateInput';
|
|||||||
|
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/meta-types/input/components/NumberFieldInput';
|
import { FieldInputEvent } from '@/object-record/record-field/meta-types/input/components/NumberFieldInput';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { Nullable } from 'twenty-ui/utilities';
|
import { Nullable } from 'twenty-ui/utilities';
|
||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
import { useDateTimeField } from '../../hooks/useDateTimeField';
|
import { useDateTimeField } from '../../hooks/useDateTimeField';
|
||||||
@ -25,6 +27,10 @@ export const DateTimeFieldInput = ({
|
|||||||
}: DateTimeFieldInputProps) => {
|
}: DateTimeFieldInputProps) => {
|
||||||
const { fieldValue, setDraftValue } = useDateTimeField();
|
const { fieldValue, setDraftValue } = useDateTimeField();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
|
|
||||||
const persistDate = (newDate: Nullable<Date>) => {
|
const persistDate = (newDate: Nullable<Date>) => {
|
||||||
@ -68,6 +74,7 @@ export const DateTimeFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DateInput
|
<DateInput
|
||||||
|
instanceId={instanceId}
|
||||||
onClickOutside={handleClickOutside}
|
onClickOutside={handleClickOutside}
|
||||||
onEnter={handleEnter}
|
onEnter={handleEnter}
|
||||||
onEscape={handleEscape}
|
onEscape={handleEscape}
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import { DoubleTextInput } from '@/ui/field/input/components/DoubleTextInput';
|
|||||||
import { FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/FirstNamePlaceholder';
|
import { FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/FirstNamePlaceholder';
|
||||||
import { LAST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/LastNamePlaceholder';
|
import { LAST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS } from '@/object-record/record-field/meta-types/input/constants/LastNamePlaceholder';
|
||||||
import { isDoubleTextFieldEmpty } from '@/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty';
|
import { isDoubleTextFieldEmpty } from '@/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
|
|
||||||
type FullNameFieldInputProps = {
|
type FullNameFieldInputProps = {
|
||||||
onClickOutside?: FieldInputClickOutsideEvent;
|
onClickOutside?: FieldInputClickOutsideEvent;
|
||||||
@ -78,8 +80,13 @@ export const FullNameFieldInput = ({
|
|||||||
setDraftValue(getRequiredDraftValueFromDoubleText(newDoubleText));
|
setDraftValue(getRequiredDraftValueFromDoubleText(newDoubleText));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DoubleTextInput
|
<DoubleTextInput
|
||||||
|
instanceId={instanceId}
|
||||||
firstValue={draftValue?.firstName ?? ''}
|
firstValue={draftValue?.firstName ?? ''}
|
||||||
secondValue={draftValue?.lastName ?? ''}
|
secondValue={draftValue?.lastName ?? ''}
|
||||||
firstValuePlaceholder={
|
firstValuePlaceholder={
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import styled from '@emotion/styled';
|
|||||||
import { forwardRef, InputHTMLAttributes, ReactNode, useRef } from 'react';
|
import { forwardRef, InputHTMLAttributes, ReactNode, useRef } from 'react';
|
||||||
|
|
||||||
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
|
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
|
||||||
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
|
|
||||||
import { TEXT_INPUT_STYLE } from 'twenty-ui/theme';
|
import { TEXT_INPUT_STYLE } from 'twenty-ui/theme';
|
||||||
|
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
|
||||||
|
|
||||||
const StyledInput = styled.input<{
|
const StyledInput = styled.input<{
|
||||||
withRightComponent?: boolean;
|
withRightComponent?: boolean;
|
||||||
@ -84,6 +84,7 @@ export type MultiItemBaseInputProps = Omit<HTMLInputProps, 'onChange'> & {
|
|||||||
hasError?: boolean;
|
hasError?: boolean;
|
||||||
hasItem: boolean;
|
hasItem: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
|
instanceId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MultiItemBaseInput = forwardRef<
|
export const MultiItemBaseInput = forwardRef<
|
||||||
@ -108,6 +109,7 @@ export const MultiItemBaseInput = forwardRef<
|
|||||||
error = '',
|
error = '',
|
||||||
hasError = false,
|
hasError = false,
|
||||||
hasItem,
|
hasItem,
|
||||||
|
instanceId,
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
) => {
|
) => {
|
||||||
@ -115,6 +117,7 @@ export const MultiItemBaseInput = forwardRef<
|
|||||||
const combinedRef = useCombinedRefs(ref, inputRef);
|
const combinedRef = useCombinedRefs(ref, inputRef);
|
||||||
|
|
||||||
useRegisterInputEvents({
|
useRegisterInputEvents({
|
||||||
|
focusId: instanceId,
|
||||||
inputRef,
|
inputRef,
|
||||||
inputValue: value,
|
inputValue: value,
|
||||||
onEnter,
|
onEnter,
|
||||||
|
|||||||
@ -6,13 +6,15 @@ import {
|
|||||||
MultiItemBaseInput,
|
MultiItemBaseInput,
|
||||||
MultiItemBaseInputProps,
|
MultiItemBaseInputProps,
|
||||||
} from '@/object-record/record-field/meta-types/input/components/MultiItemBaseInput';
|
} from '@/object-record/record-field/meta-types/input/components/MultiItemBaseInput';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { PhoneRecord } from '@/object-record/record-field/types/FieldMetadata';
|
import { PhoneRecord } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { IconCheck, IconPlus } from 'twenty-ui/display';
|
import { IconCheck, IconPlus } from 'twenty-ui/display';
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
@ -79,7 +81,17 @@ export const MultiItemFieldInput = <T,>({
|
|||||||
listenerId: hotkeyScope,
|
listenerId: hotkeyScope,
|
||||||
});
|
});
|
||||||
|
|
||||||
useScopedHotkeys(Key.Escape, handleDropdownClose, hotkeyScope);
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
focusId: instanceId,
|
||||||
|
keys: [Key.Escape],
|
||||||
|
callback: handleDropdownClose,
|
||||||
|
scope: hotkeyScope,
|
||||||
|
dependencies: [handleDropdownClose],
|
||||||
|
});
|
||||||
|
|
||||||
const [isInputDisplayed, setIsInputDisplayed] = useState(false);
|
const [isInputDisplayed, setIsInputDisplayed] = useState(false);
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
@ -204,6 +216,7 @@ export const MultiItemFieldInput = <T,>({
|
|||||||
)}
|
)}
|
||||||
{isInputDisplayed || !items.length ? (
|
{isInputDisplayed || !items.length ? (
|
||||||
<MultiItemBaseInput
|
<MultiItemBaseInput
|
||||||
|
instanceId={instanceId}
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField';
|
import { useMultiSelectField } from '@/object-record/record-field/meta-types/hooks/useMultiSelectField';
|
||||||
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { MultiSelectInput } from '@/ui/field/input/components/MultiSelectInput';
|
import { MultiSelectInput } from '@/ui/field/input/components/MultiSelectInput';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
|
|
||||||
type MultiSelectFieldInputProps = {
|
type MultiSelectFieldInputProps = {
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
@ -10,18 +11,18 @@ type MultiSelectFieldInputProps = {
|
|||||||
export const MultiSelectFieldInput = ({
|
export const MultiSelectFieldInput = ({
|
||||||
onCancel,
|
onCancel,
|
||||||
}: MultiSelectFieldInputProps) => {
|
}: MultiSelectFieldInputProps) => {
|
||||||
const { persistField, fieldDefinition, fieldValues, recordId } =
|
const { persistField, fieldDefinition, fieldValues } = useMultiSelectField();
|
||||||
useMultiSelectField();
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiSelectInput
|
<MultiSelectInput
|
||||||
selectableListComponentInstanceId={
|
selectableListComponentInstanceId={
|
||||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||||
}
|
}
|
||||||
focusId={getFieldInputInstanceId({
|
focusId={instanceId}
|
||||||
recordId,
|
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
|
||||||
})}
|
|
||||||
options={fieldDefinition.metadata.options}
|
options={fieldDefinition.metadata.options}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onOptionSelected={persistField}
|
onOptionSelected={persistField}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { TextInput } from '@/ui/field/input/components/TextInput';
|
import { TextInput } from '@/ui/field/input/components/TextInput';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useNumberField } from '../../hooks/useNumberField';
|
import { useNumberField } from '../../hooks/useNumberField';
|
||||||
|
|
||||||
export type FieldInputEvent = (persist: () => void) => void;
|
export type FieldInputEvent = (persist: () => void) => void;
|
||||||
@ -25,6 +27,10 @@ export const NumberFieldInput = ({
|
|||||||
const { fieldDefinition, draftValue, setDraftValue, persistNumberField } =
|
const { fieldDefinition, draftValue, setDraftValue, persistNumberField } =
|
||||||
useNumberField();
|
useNumberField();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const handleEnter = (newText: string) => {
|
const handleEnter = (newText: string) => {
|
||||||
onEnter?.(() => persistNumberField(newText));
|
onEnter?.(() => persistNumberField(newText));
|
||||||
};
|
};
|
||||||
@ -55,6 +61,7 @@ export const NumberFieldInput = ({
|
|||||||
return (
|
return (
|
||||||
<FieldInputContainer>
|
<FieldInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={instanceId}
|
||||||
placeholder={fieldDefinition.metadata.placeHolder}
|
placeholder={fieldDefinition.metadata.placeHolder}
|
||||||
autoFocus
|
autoFocus
|
||||||
value={draftValue?.toString() ?? ''}
|
value={draftValue?.toString() ?? ''}
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { isWorkflowRunJsonField } from '@/object-record/record-field/meta-types/utils/isWorkflowRunJsonField';
|
import { isWorkflowRunJsonField } from '@/object-record/record-field/meta-types/utils/isWorkflowRunJsonField';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
@ -70,6 +72,9 @@ export const RawJsonFieldInput = ({
|
|||||||
const hotkeyScope = DEFAULT_CELL_SCOPE.scope;
|
const hotkeyScope = DEFAULT_CELL_SCOPE.scope;
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
@ -104,32 +109,35 @@ export const RawJsonFieldInput = ({
|
|||||||
listenerId: hotkeyScope,
|
listenerId: hotkeyScope,
|
||||||
});
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
[Key.Escape],
|
keys: [Key.Escape],
|
||||||
() => {
|
callback: () => {
|
||||||
handleEscape(draftValue ?? '');
|
handleEscape(draftValue ?? '');
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[handleEscape, draftValue],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [handleEscape, draftValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'tab',
|
keys: ['tab'],
|
||||||
() => {
|
callback: () => {
|
||||||
handleTab(draftValue ?? '');
|
handleTab(draftValue ?? '');
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[handleTab, draftValue],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [handleTab, draftValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'shift+tab',
|
keys: ['shift+tab'],
|
||||||
() => {
|
callback: () => {
|
||||||
handleShiftTab(draftValue ?? '');
|
handleShiftTab(draftValue ?? '');
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[handleShiftTab, draftValue],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [handleShiftTab, draftValue],
|
||||||
|
});
|
||||||
|
|
||||||
const showEditingButton = !isWorkflowRunJsonField({
|
const showEditingButton = !isWorkflowRunJsonField({
|
||||||
objectMetadataNameSingular:
|
objectMetadataNameSingular:
|
||||||
|
|||||||
@ -10,14 +10,15 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
|
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
|
||||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
||||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
@ -31,10 +32,9 @@ export const RelationFromManyFieldInput = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}: RelationFromManyFieldInputProps) => {
|
}: RelationFromManyFieldInputProps) => {
|
||||||
const { fieldDefinition, recordId } = useContext(FieldContext);
|
const { fieldDefinition, recordId } = useContext(FieldContext);
|
||||||
const recordPickerInstanceId = getFieldInputInstanceId({
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
recordId,
|
RecordFieldComponentInstanceContext,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const { updateRelation } = useUpdateRelationFromManyFieldInput();
|
const { updateRelation } = useUpdateRelationFromManyFieldInput();
|
||||||
const fieldName = fieldDefinition.metadata.fieldName;
|
const fieldName = fieldDefinition.metadata.fieldName;
|
||||||
@ -94,7 +94,7 @@ export const RelationFromManyFieldInput = ({
|
|||||||
const multipleRecordPickerPickableMorphItemsCallbackState =
|
const multipleRecordPickerPickableMorphItemsCallbackState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
multipleRecordPickerPickableMorphItemsComponentState,
|
multipleRecordPickerPickableMorphItemsComponentState,
|
||||||
recordPickerInstanceId,
|
instanceId,
|
||||||
);
|
);
|
||||||
const { performSearch: multipleRecordPickerPerformSearch } =
|
const { performSearch: multipleRecordPickerPerformSearch } =
|
||||||
useMultipleRecordPickerPerformSearch();
|
useMultipleRecordPickerPerformSearch();
|
||||||
@ -123,7 +123,7 @@ export const RelationFromManyFieldInput = ({
|
|||||||
set(multipleRecordPickerPickableMorphItemsCallbackState, newMorphItems);
|
set(multipleRecordPickerPickableMorphItemsCallbackState, newMorphItems);
|
||||||
|
|
||||||
multipleRecordPickerPerformSearch({
|
multipleRecordPickerPerformSearch({
|
||||||
multipleRecordPickerInstanceId: recordPickerInstanceId,
|
multipleRecordPickerInstanceId: instanceId,
|
||||||
forceSearchFilter: searchInput,
|
forceSearchFilter: searchInput,
|
||||||
forceSearchableObjectMetadataItems: [relationObjectMetadataItem],
|
forceSearchableObjectMetadataItems: [relationObjectMetadataItem],
|
||||||
forcePickableMorphItems: newMorphItems,
|
forcePickableMorphItems: newMorphItems,
|
||||||
@ -132,7 +132,7 @@ export const RelationFromManyFieldInput = ({
|
|||||||
[
|
[
|
||||||
createNewRecordAndOpenRightDrawer,
|
createNewRecordAndOpenRightDrawer,
|
||||||
relationObjectMetadataItem,
|
relationObjectMetadataItem,
|
||||||
recordPickerInstanceId,
|
instanceId,
|
||||||
multipleRecordPickerPickableMorphItemsCallbackState,
|
multipleRecordPickerPickableMorphItemsCallbackState,
|
||||||
multipleRecordPickerPerformSearch,
|
multipleRecordPickerPerformSearch,
|
||||||
],
|
],
|
||||||
@ -142,15 +142,15 @@ export const RelationFromManyFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MultipleRecordPicker
|
<MultipleRecordPicker
|
||||||
focusId={recordPickerInstanceId}
|
focusId={instanceId}
|
||||||
componentInstanceId={recordPickerInstanceId}
|
componentInstanceId={instanceId}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onChange={(morphItem) => {
|
onChange={(morphItem) => {
|
||||||
if (isRelationFromActivityTargets) {
|
if (isRelationFromActivityTargets) {
|
||||||
updateActivityTargetFromCell({
|
updateActivityTargetFromCell({
|
||||||
morphItem,
|
morphItem,
|
||||||
activityTargetWithTargetRecords: activityTargetObjectRecords,
|
activityTargetWithTargetRecords: activityTargetObjectRecords,
|
||||||
recordPickerInstanceId,
|
recordPickerInstanceId: instanceId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
updateRelation(morphItem);
|
updateRelation(morphItem);
|
||||||
|
|||||||
@ -3,14 +3,15 @@ import { useRelationField } from '../../hooks/useRelationField';
|
|||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
||||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -29,10 +30,9 @@ export const RelationToOneFieldInput = ({
|
|||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
|
|
||||||
const recordPickerInstanceId = getFieldInputInstanceId({
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
recordId,
|
RecordFieldComponentInstanceContext,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const handleRecordSelected = (
|
const handleRecordSelected = (
|
||||||
selectedRecord: SingleRecordPickerRecord | null | undefined,
|
selectedRecord: SingleRecordPickerRecord | null | undefined,
|
||||||
@ -67,7 +67,7 @@ export const RelationToOneFieldInput = ({
|
|||||||
|
|
||||||
const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2(
|
const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2(
|
||||||
singleRecordPickerSelectedIdComponentState,
|
singleRecordPickerSelectedIdComponentState,
|
||||||
recordPickerInstanceId,
|
instanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCreateNew = async (searchInput?: string) => {
|
const handleCreateNew = async (searchInput?: string) => {
|
||||||
@ -84,8 +84,8 @@ export const RelationToOneFieldInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleRecordPicker
|
<SingleRecordPicker
|
||||||
focusId={recordPickerInstanceId}
|
focusId={instanceId}
|
||||||
componentInstanceId={recordPickerInstanceId}
|
componentInstanceId={instanceId}
|
||||||
EmptyIcon={IconForbid}
|
EmptyIcon={IconForbid}
|
||||||
emptyLabel={'No ' + fieldDefinition.label}
|
emptyLabel={'No ' + fieldDefinition.label}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
@ -94,7 +94,7 @@ export const RelationToOneFieldInput = ({
|
|||||||
objectNameSingular={
|
objectNameSingular={
|
||||||
fieldDefinition.metadata.relationObjectMetadataNameSingular
|
fieldDefinition.metadata.relationObjectMetadataNameSingular
|
||||||
}
|
}
|
||||||
recordPickerInstanceId={recordPickerInstanceId}
|
recordPickerInstanceId={instanceId}
|
||||||
layoutDirection={
|
layoutDirection={
|
||||||
layoutDirection === 'downward'
|
layoutDirection === 'downward'
|
||||||
? 'search-bar-on-top'
|
? 'search-bar-on-top'
|
||||||
|
|||||||
@ -3,14 +3,16 @@ import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableE
|
|||||||
import { useRichTextCommandMenu } from '@/command-menu/hooks/useRichTextCommandMenu';
|
import { useRichTextCommandMenu } from '@/command-menu/hooks/useRichTextCommandMenu';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
|
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { lazy, Suspense, useRef } from 'react';
|
import { Suspense, lazy, useRef } from 'react';
|
||||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||||
import { IconLayoutSidebarLeftCollapse } from 'twenty-ui/display';
|
import { IconLayoutSidebarLeftCollapse } from 'twenty-ui/display';
|
||||||
import { FloatingIconButton } from 'twenty-ui/input';
|
import { FloatingIconButton } from 'twenty-ui/input';
|
||||||
@ -72,6 +74,9 @@ export const RichTextFieldInput = ({
|
|||||||
} & RichTextFieldInputProps) => {
|
} & RichTextFieldInputProps) => {
|
||||||
const { editRichText } = useRichTextCommandMenu();
|
const { editRichText } = useRichTextCommandMenu();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
|
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
|
||||||
onClickOutside?.(() => {}, event);
|
onClickOutside?.(() => {}, event);
|
||||||
@ -82,6 +87,7 @@ export const RichTextFieldInput = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useRegisterInputEvents({
|
useRegisterInputEvents({
|
||||||
|
focusId: instanceId,
|
||||||
inputRef: containerRef,
|
inputRef: containerRef,
|
||||||
inputValue: null,
|
inputValue: null,
|
||||||
onClickOutside: handleClickOutside,
|
onClickOutside: handleClickOutside,
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { useClearField } from '@/object-record/record-field/hooks/useClearField';
|
import { useClearField } from '@/object-record/record-field/hooks/useClearField';
|
||||||
import { useSelectField } from '@/object-record/record-field/meta-types/hooks/useSelectField';
|
import { useSelectField } from '@/object-record/record-field/meta-types/hooks/useSelectField';
|
||||||
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
import { SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID } from '@/object-record/record-field/meta-types/input/constants/SelectFieldInputSelectableListComponentInstanceId';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { SelectInput } from '@/ui/field/input/components/SelectInput';
|
import { SelectInput } from '@/ui/field/input/components/SelectInput';
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -21,8 +22,11 @@ export const SelectFieldInput = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
}: SelectFieldInputProps) => {
|
}: SelectFieldInputProps) => {
|
||||||
const { persistField, fieldDefinition, fieldValue, recordId } =
|
const { persistField, fieldDefinition, fieldValue } = useSelectField();
|
||||||
useSelectField();
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([]);
|
const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([]);
|
||||||
|
|
||||||
@ -46,15 +50,16 @@ export const SelectFieldInput = ({
|
|||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
};
|
};
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
Key.Escape,
|
keys: [Key.Escape],
|
||||||
() => {
|
callback: () => {
|
||||||
onCancel?.();
|
onCancel?.();
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
},
|
},
|
||||||
DEFAULT_CELL_SCOPE.scope,
|
scope: DEFAULT_CELL_SCOPE.scope,
|
||||||
[onCancel, resetSelectedItem],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [onCancel, resetSelectedItem],
|
||||||
|
});
|
||||||
|
|
||||||
const optionIds = [
|
const optionIds = [
|
||||||
`No ${fieldDefinition.label}`,
|
`No ${fieldDefinition.label}`,
|
||||||
@ -67,10 +72,7 @@ export const SelectFieldInput = ({
|
|||||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||||
}
|
}
|
||||||
selectableItemIdArray={optionIds}
|
selectableItemIdArray={optionIds}
|
||||||
focusId={getFieldInputInstanceId({
|
focusId={instanceId}
|
||||||
recordId,
|
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
|
||||||
})}
|
|
||||||
onEnter={(itemId) => {
|
onEnter={(itemId) => {
|
||||||
const option = filteredOptions.find(
|
const option = filteredOptions.find(
|
||||||
(option) => option.value === itemId,
|
(option) => option.value === itemId,
|
||||||
|
|||||||
@ -3,12 +3,14 @@ import { TextAreaInput } from '@/ui/field/input/components/TextAreaInput';
|
|||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
import { useTextField } from '../../hooks/useTextField';
|
import { useTextField } from '../../hooks/useTextField';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import {
|
import {
|
||||||
FieldInputClickOutsideEvent,
|
FieldInputClickOutsideEvent,
|
||||||
FieldInputEvent,
|
FieldInputEvent,
|
||||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { turnIntoUndefinedIfWhitespacesOnly } from '~/utils/string/turnIntoUndefinedIfWhitespacesOnly';
|
import { turnIntoUndefinedIfWhitespacesOnly } from '~/utils/string/turnIntoUndefinedIfWhitespacesOnly';
|
||||||
|
|
||||||
export type TextFieldInputProps = {
|
export type TextFieldInputProps = {
|
||||||
@ -28,6 +30,10 @@ export const TextFieldInput = ({
|
|||||||
}: TextFieldInputProps) => {
|
}: TextFieldInputProps) => {
|
||||||
const { fieldDefinition, draftValue, setDraftValue } = useTextField();
|
const { fieldDefinition, draftValue, setDraftValue } = useTextField();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
const handleEnter = (newText: string) => {
|
const handleEnter = (newText: string) => {
|
||||||
onEnter?.(() => persistField(newText.trim()));
|
onEnter?.(() => persistField(newText.trim()));
|
||||||
@ -59,6 +65,7 @@ export const TextFieldInput = ({
|
|||||||
return (
|
return (
|
||||||
<FieldInputContainer>
|
<FieldInputContainer>
|
||||||
<TextAreaInput
|
<TextAreaInput
|
||||||
|
instanceId={instanceId}
|
||||||
placeholder={fieldDefinition.metadata.placeHolder}
|
placeholder={fieldDefinition.metadata.placeHolder}
|
||||||
autoFocus
|
autoFocus
|
||||||
value={draftValue ?? ''}
|
value={draftValue ?? ''}
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||||
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import {
|
import {
|
||||||
AddressInput,
|
AddressInput,
|
||||||
AddressInputProps,
|
AddressInputProps,
|
||||||
} from '@/ui/field/input/components/AddressInput';
|
} from '@/ui/field/input/components/AddressInput';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
const AddressValueSetterEffect = ({
|
const AddressValueSetterEffect = ({
|
||||||
@ -43,21 +45,30 @@ const AddressInputWithContext = ({
|
|||||||
onTab,
|
onTab,
|
||||||
onShiftTab,
|
onShiftTab,
|
||||||
}: AddressInputWithContextProps) => {
|
}: AddressInputWithContextProps) => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId: recordId ?? '',
|
||||||
|
fieldName: 'Address',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotKeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotKeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [instanceId, pushFocusItemToFocusStack]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId ?? '',
|
|
||||||
'Address',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
@ -80,6 +91,7 @@ const AddressInputWithContext = ({
|
|||||||
>
|
>
|
||||||
<AddressValueSetterEffect value={value} />
|
<AddressValueSetterEffect value={value} />
|
||||||
<AddressInput
|
<AddressInput
|
||||||
|
instanceId={instanceId}
|
||||||
onEnter={onEnter}
|
onEnter={onEnter}
|
||||||
onEscape={onEscape}
|
onEscape={onEscape}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
@ -116,7 +128,16 @@ const meta: Meta = {
|
|||||||
title: 'UI/Data/Field/Input/AddressFieldInput',
|
title: 'UI/Data/Field/Input/AddressFieldInput',
|
||||||
component: AddressInputWithContext,
|
component: AddressInputWithContext,
|
||||||
args: {
|
args: {
|
||||||
value: 'text',
|
value: {
|
||||||
|
addressStreet1: 'Address 1',
|
||||||
|
addressStreet2: null,
|
||||||
|
addressCity: null,
|
||||||
|
addressState: null,
|
||||||
|
addressPostcode: null,
|
||||||
|
addressCountry: null,
|
||||||
|
addressLat: null,
|
||||||
|
addressLng: null,
|
||||||
|
},
|
||||||
onEnter: enterJestFn,
|
onEnter: enterJestFn,
|
||||||
onEscape: escapeJestfn,
|
onEscape: escapeJestfn,
|
||||||
onClickOutside: clickOutsideJestFn,
|
onClickOutside: clickOutsideJestFn,
|
||||||
@ -148,7 +169,10 @@ export const Enter: Story = {
|
|||||||
|
|
||||||
expect(enterJestFn).toHaveBeenCalledTimes(0);
|
expect(enterJestFn).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
await canvas.findByText('Address 1');
|
const addressInput = await canvas.findByDisplayValue('Address 1');
|
||||||
|
|
||||||
|
await userEvent.click(addressInput);
|
||||||
|
|
||||||
await userEvent.keyboard('{enter}');
|
await userEvent.keyboard('{enter}');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
|||||||
@ -6,9 +6,11 @@ import { useEffect } from 'react';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useArrayField } from '@/object-record/record-field/meta-types/hooks/useArrayField';
|
import { useArrayField } from '@/object-record/record-field/meta-types/hooks/useArrayField';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { ArrayFieldInput } from '../ArrayFieldInput';
|
import { ArrayFieldInput } from '../ArrayFieldInput';
|
||||||
|
|
||||||
@ -55,20 +57,33 @@ const ArrayInputWithContext = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: ArrayInputWithContextProps) => {
|
}: ArrayInputWithContextProps) => {
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'tags',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotkeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
'tags',
|
fieldName: 'tags',
|
||||||
'record-table-cell',
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
|
|||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import {
|
import {
|
||||||
BooleanFieldInput,
|
BooleanFieldInput,
|
||||||
BooleanFieldInputProps,
|
BooleanFieldInputProps,
|
||||||
@ -43,11 +44,11 @@ const BooleanFieldInputWithContext = ({
|
|||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId ?? '',
|
recordId: recordId ?? '',
|
||||||
'Boolean',
|
fieldName: 'Boolean',
|
||||||
'record-table-cell',
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -2,13 +2,15 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { expect, fn, userEvent, within } from '@storybook/test';
|
import { expect, fn, userEvent, within } from '@storybook/test';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
||||||
import { useDateTimeField } from '../../../hooks/useDateTimeField';
|
import { useDateTimeField } from '../../../hooks/useDateTimeField';
|
||||||
import {
|
import {
|
||||||
@ -52,7 +54,7 @@ const DateFieldValueGater = ({
|
|||||||
|
|
||||||
type DateFieldInputWithContextProps = DateTimeFieldInputProps & {
|
type DateFieldInputWithContextProps = DateTimeFieldInputProps & {
|
||||||
value: Date;
|
value: Date;
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DateFieldInputWithContext = ({
|
const DateFieldInputWithContext = ({
|
||||||
@ -62,20 +64,28 @@ const DateFieldInputWithContext = ({
|
|||||||
onEnter,
|
onEnter,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: DateFieldInputWithContextProps) => {
|
}: DateFieldInputWithContextProps) => {
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'Date',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotkeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId ?? '',
|
|
||||||
'Date',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
@ -91,7 +101,7 @@ const DateFieldInputWithContext = ({
|
|||||||
objectMetadataNameSingular: 'person',
|
objectMetadataNameSingular: 'person',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
recordId: '123',
|
recordId,
|
||||||
isLabelIdentifier: false,
|
isLabelIdentifier: false,
|
||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -8,9 +8,11 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { useEmailsField } from '@/object-record/record-field/meta-types/hooks/useEmailsField';
|
import { useEmailsField } from '@/object-record/record-field/meta-types/hooks/useEmailsField';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldEmailsValue } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldEmailsValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { EmailsFieldInput } from '../EmailsFieldInput';
|
import { EmailsFieldInput } from '../EmailsFieldInput';
|
||||||
|
|
||||||
@ -57,20 +59,28 @@ const EmailInputWithContext = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: EmailInputWithContextProps) => {
|
}: EmailInputWithContextProps) => {
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'emails',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotkeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId,
|
|
||||||
'emails',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -5,9 +5,11 @@ import { useEffect } from 'react';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useLinksField } from '@/object-record/record-field/meta-types/hooks/useLinksField';
|
import { useLinksField } from '@/object-record/record-field/meta-types/hooks/useLinksField';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { getCanvasElementForDropdownTesting } from 'twenty-ui/testing';
|
import { getCanvasElementForDropdownTesting } from 'twenty-ui/testing';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { LinksFieldInput } from '../LinksFieldInput';
|
import { LinksFieldInput } from '../LinksFieldInput';
|
||||||
@ -38,7 +40,7 @@ type LinksInputWithContextProps = {
|
|||||||
primaryLinkLabel: string | null;
|
primaryLinkLabel: string | null;
|
||||||
secondaryLinks: Array<{ url: string | null; label: string | null }> | null;
|
secondaryLinks: Array<{ url: string | null; label: string | null }> | null;
|
||||||
};
|
};
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
onClickOutside?: (event: MouseEvent | TouchEvent) => void;
|
onClickOutside?: (event: MouseEvent | TouchEvent) => void;
|
||||||
};
|
};
|
||||||
@ -67,21 +69,29 @@ const LinksInputWithContext = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: LinksInputWithContextProps) => {
|
}: LinksInputWithContextProps) => {
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'Links',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotkeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId ?? '',
|
|
||||||
'Links',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
@ -97,7 +107,7 @@ const LinksInputWithContext = ({
|
|||||||
objectMetadataNameSingular: 'company',
|
objectMetadataNameSingular: 'company',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
recordId: recordId ?? '123',
|
recordId,
|
||||||
isLabelIdentifier: false,
|
isLabelIdentifier: false,
|
||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
useUpdateRecord: () => [updateRecord, { loading: false }],
|
useUpdateRecord: () => [updateRecord, { loading: false }],
|
||||||
@ -131,6 +141,7 @@ const meta: Meta = {
|
|||||||
primaryLinkLabel: null,
|
primaryLinkLabel: null,
|
||||||
secondaryLinks: null,
|
secondaryLinks: null,
|
||||||
},
|
},
|
||||||
|
recordId: '123',
|
||||||
onCancel: cancelJestFn,
|
onCancel: cancelJestFn,
|
||||||
onClickOutside: clickOutsideJestFn,
|
onClickOutside: clickOutsideJestFn,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,14 +2,16 @@ import { Decorator, Meta, StoryObj } from '@storybook/react';
|
|||||||
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { useNumberField } from '../../../hooks/useNumberField';
|
import { useNumberField } from '../../../hooks/useNumberField';
|
||||||
@ -27,7 +29,7 @@ const NumberFieldValueSetterEffect = ({ value }: { value: number }) => {
|
|||||||
|
|
||||||
type NumberFieldInputWithContextProps = NumberFieldInputProps & {
|
type NumberFieldInputWithContextProps = NumberFieldInputProps & {
|
||||||
value: number;
|
value: number;
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const NumberFieldInputWithContext = ({
|
const NumberFieldInputWithContext = ({
|
||||||
@ -39,25 +41,38 @@ const NumberFieldInputWithContext = ({
|
|||||||
onTab,
|
onTab,
|
||||||
onShiftTab,
|
onShiftTab,
|
||||||
}: NumberFieldInputWithContextProps) => {
|
}: NumberFieldInputWithContextProps) => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'Number',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
setHotKeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
setIsReady(true);
|
setIsReady(true);
|
||||||
}
|
}
|
||||||
}, [isReady, setHotKeyScope]);
|
}, [isReady, pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId ?? '',
|
recordId,
|
||||||
'Number',
|
fieldName: 'Number',
|
||||||
'record-table-cell',
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -9,9 +9,11 @@ import { usePhonesField } from '@/object-record/record-field/meta-types/hooks/us
|
|||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { PhonesFieldInput } from '../PhonesFieldInput';
|
import { PhonesFieldInput } from '../PhonesFieldInput';
|
||||||
|
|
||||||
@ -58,20 +60,28 @@ const PhoneInputWithContext = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: PhoneInputWithContextProps) => {
|
}: PhoneInputWithContextProps) => {
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'phones',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotkeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId,
|
|
||||||
'phones',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -2,12 +2,14 @@ import { Decorator, Meta, StoryObj } from '@storybook/react';
|
|||||||
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
import { FieldRatingValue } from '../../../../types/FieldMetadata';
|
import { FieldRatingValue } from '../../../../types/FieldMetadata';
|
||||||
import { useRatingField } from '../../../hooks/useRatingField';
|
import { useRatingField } from '../../../hooks/useRatingField';
|
||||||
@ -29,7 +31,7 @@ const RatingFieldValueSetterEffect = ({
|
|||||||
|
|
||||||
type RatingFieldInputWithContextProps = RatingFieldInputProps & {
|
type RatingFieldInputWithContextProps = RatingFieldInputProps & {
|
||||||
value: FieldRatingValue;
|
value: FieldRatingValue;
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RatingFieldInputWithContext = ({
|
const RatingFieldInputWithContext = ({
|
||||||
@ -37,20 +39,29 @@ const RatingFieldInputWithContext = ({
|
|||||||
value,
|
value,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
}: RatingFieldInputWithContextProps) => {
|
}: RatingFieldInputWithContextProps) => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'Rating',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotKeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotKeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: instanceId,
|
||||||
recordId ?? '',
|
|
||||||
'Rating',
|
|
||||||
'record-table-cell',
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { RelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput';
|
import { RelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
@ -19,9 +19,9 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
import { RelationType } from '~/generated-metadata/graphql';
|
import { RelationType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ const RelationWorkspaceSetterEffect = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const RelationManyFieldInputWithContext = () => {
|
const RelationManyFieldInputWithContext = () => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
const fieldDefinition = useMemo(
|
const fieldDefinition = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -72,7 +72,14 @@ const RelationManyFieldInputWithContext = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRecordStoreFieldValue([]);
|
setRecordStoreFieldValue([]);
|
||||||
|
|
||||||
setHotKeyScope(DropdownHotkeyScope.Dropdown);
|
pushFocusItemToFocusStack({
|
||||||
|
focusId: 'relation-from-many-field-input',
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: 'relation-from-many-field-input',
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
openFieldInput({
|
openFieldInput({
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
recordId: 'recordId',
|
recordId: 'recordId',
|
||||||
@ -80,7 +87,7 @@ const RelationManyFieldInputWithContext = () => {
|
|||||||
}, [
|
}, [
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
openFieldInput,
|
openFieldInput,
|
||||||
setHotKeyScope,
|
pushFocusItemToFocusStack,
|
||||||
setRecordStoreFieldValue,
|
setRecordStoreFieldValue,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -88,10 +95,7 @@ const RelationManyFieldInputWithContext = () => {
|
|||||||
<div>
|
<div>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getFieldInputInstanceId({
|
instanceId: 'relation-from-many-field-input',
|
||||||
recordId: 'recordId',
|
|
||||||
fieldName: 'people',
|
|
||||||
}),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
@ -68,24 +67,13 @@ const RelationToOneFieldInputWithContext = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getFieldInputInstanceId({
|
focusId: 'relation-to-one-field-input',
|
||||||
recordId: '123',
|
|
||||||
fieldName: 'Relation',
|
|
||||||
}),
|
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.DROPDOWN,
|
type: FocusComponentType.DROPDOWN,
|
||||||
instanceId: getFieldInputInstanceId({
|
instanceId: 'relation-to-one-field-input',
|
||||||
recordId: '123',
|
|
||||||
fieldName: 'Relation',
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
hotkeyScope: {
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
scope: DropdownHotkeyScope.Dropdown,
|
memoizeKey: 'relation-to-one-field-input',
|
||||||
},
|
|
||||||
memoizeKey: getFieldInputInstanceId({
|
|
||||||
recordId: '123',
|
|
||||||
fieldName: 'Relation',
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
}, [pushFocusItemToFocusStack]);
|
}, [pushFocusItemToFocusStack]);
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,11 @@ import { useEffect } from 'react';
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
@ -35,16 +38,29 @@ const RichTextFieldInputWithContext = ({
|
|||||||
onClickOutside,
|
onClickOutside,
|
||||||
onEscape,
|
onEscape,
|
||||||
}: RichTextFieldInputWithContextProps) => {
|
}: RichTextFieldInputWithContextProps) => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId: targetableObjectId,
|
||||||
|
fieldName: 'richText',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHotKeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
}, [setHotKeyScope]);
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
}, [pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: 'record-field-component-instance-id',
|
instanceId: instanceId,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { useTextField } from '../../../hooks/useTextField';
|
import { useTextField } from '../../../hooks/useTextField';
|
||||||
import { TextFieldInput, TextFieldInputProps } from '../TextFieldInput';
|
import { TextFieldInput, TextFieldInputProps } from '../TextFieldInput';
|
||||||
|
|
||||||
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = useTextField();
|
const { setFieldValue } = useTextField();
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
|||||||
|
|
||||||
type TextFieldInputWithContextProps = TextFieldInputProps & {
|
type TextFieldInputWithContextProps = TextFieldInputProps & {
|
||||||
value: string;
|
value: string;
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TextFieldInputWithContext = ({
|
const TextFieldInputWithContext = ({
|
||||||
@ -37,26 +39,39 @@ const TextFieldInputWithContext = ({
|
|||||||
onTab,
|
onTab,
|
||||||
onShiftTab,
|
onShiftTab,
|
||||||
}: TextFieldInputWithContextProps) => {
|
}: TextFieldInputWithContextProps) => {
|
||||||
const setHotKeyScope = useSetHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: 'Text',
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
setHotKeyScope(DEFAULT_CELL_SCOPE.scope);
|
pushFocusItemToFocusStack({
|
||||||
|
focusId: instanceId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: instanceId,
|
||||||
|
},
|
||||||
|
hotkeyScope: DEFAULT_CELL_SCOPE,
|
||||||
|
});
|
||||||
|
|
||||||
setIsReady(true);
|
setIsReady(true);
|
||||||
}
|
}
|
||||||
}, [isReady, setHotKeyScope]);
|
}, [isReady, pushFocusItemToFocusStack, instanceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: 'record-field-component-instance-id',
|
instanceId: instanceId,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
value={{
|
value={{
|
||||||
recordId: recordId ?? '123',
|
recordId,
|
||||||
fieldDefinition: {
|
fieldDefinition: {
|
||||||
fieldMetadataId: 'text',
|
fieldMetadataId: 'text',
|
||||||
label: 'Text',
|
label: 'Text',
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
FieldRelationFromManyValue,
|
FieldRelationFromManyValue,
|
||||||
FieldRelationValue,
|
FieldRelationValue,
|
||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { useMultipleRecordPickerOpen } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen';
|
import { useMultipleRecordPickerOpen } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen';
|
||||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
@ -11,6 +10,7 @@ import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from
|
|||||||
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
@ -28,14 +28,17 @@ export const useOpenRelationFromManyFieldInput = () => {
|
|||||||
fieldName,
|
fieldName,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
recordId,
|
recordId,
|
||||||
|
prefix,
|
||||||
}: {
|
}: {
|
||||||
fieldName: string;
|
fieldName: string;
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
recordId: string;
|
recordId: string;
|
||||||
|
prefix?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const recordPickerInstanceId = getFieldInputInstanceId({
|
const recordPickerInstanceId = getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName,
|
fieldName,
|
||||||
|
prefix,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fieldValue = snapshot
|
const fieldValue = snapshot
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import {
|
|||||||
FieldRelationToOneValue,
|
FieldRelationToOneValue,
|
||||||
FieldRelationValue,
|
FieldRelationValue,
|
||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
|
||||||
import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen';
|
import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen';
|
||||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
@ -18,10 +18,19 @@ export const useOpenRelationToOneFieldInput = () => {
|
|||||||
|
|
||||||
const openRelationToOneFieldInput = useRecoilCallback(
|
const openRelationToOneFieldInput = useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
({ fieldName, recordId }: { fieldName: string; recordId: string }) => {
|
({
|
||||||
const recordPickerInstanceId = getFieldInputInstanceId({
|
fieldName,
|
||||||
|
recordId,
|
||||||
|
prefix,
|
||||||
|
}: {
|
||||||
|
fieldName: string;
|
||||||
|
recordId: string;
|
||||||
|
prefix?: string;
|
||||||
|
}) => {
|
||||||
|
const recordPickerInstanceId = getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName,
|
fieldName,
|
||||||
|
prefix,
|
||||||
});
|
});
|
||||||
const fieldValue = snapshot
|
const fieldValue = snapshot
|
||||||
.getLoadable<FieldRelationValue<FieldRelationToOneValue>>(
|
.getLoadable<FieldRelationValue<FieldRelationToOneValue>>(
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ export const useRegisterInputEvents = <T>({
|
|||||||
onTab,
|
onTab,
|
||||||
onShiftTab,
|
onShiftTab,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
|
focusId,
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: {
|
}: {
|
||||||
inputRef: React.RefObject<any>;
|
inputRef: React.RefObject<any>;
|
||||||
@ -23,6 +24,7 @@ export const useRegisterInputEvents = <T>({
|
|||||||
onTab?: (inputValue: T) => void;
|
onTab?: (inputValue: T) => void;
|
||||||
onShiftTab?: (inputValue: T) => void;
|
onShiftTab?: (inputValue: T) => void;
|
||||||
onClickOutside?: (event: MouseEvent | TouchEvent, inputValue: T) => void;
|
onClickOutside?: (event: MouseEvent | TouchEvent, inputValue: T) => void;
|
||||||
|
focusId: string;
|
||||||
hotkeyScope: string;
|
hotkeyScope: string;
|
||||||
}) => {
|
}) => {
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
@ -34,39 +36,43 @@ export const useRegisterInputEvents = <T>({
|
|||||||
listenerId: hotkeyScope,
|
listenerId: hotkeyScope,
|
||||||
});
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'enter',
|
keys: [Key.Enter],
|
||||||
() => {
|
callback: () => {
|
||||||
onEnter?.(inputValue);
|
onEnter?.(inputValue);
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
focusId,
|
||||||
[onEnter, inputValue],
|
scope: hotkeyScope,
|
||||||
);
|
dependencies: [onEnter, inputValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
[Key.Escape],
|
keys: [Key.Escape],
|
||||||
() => {
|
callback: () => {
|
||||||
onEscape?.(inputValue);
|
onEscape?.(inputValue);
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
focusId,
|
||||||
[onEscape, inputValue],
|
scope: hotkeyScope,
|
||||||
);
|
dependencies: [onEscape, inputValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'tab',
|
keys: [Key.Tab],
|
||||||
() => {
|
callback: () => {
|
||||||
onTab?.(inputValue);
|
onTab?.(inputValue);
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
focusId,
|
||||||
[onTab, inputValue],
|
scope: hotkeyScope,
|
||||||
);
|
dependencies: [onTab, inputValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'shift+tab',
|
keys: [`${Key.Shift}+${Key.Tab}`],
|
||||||
() => {
|
callback: () => {
|
||||||
onShiftTab?.(inputValue);
|
onShiftTab?.(inputValue);
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
focusId,
|
||||||
[onShiftTab, inputValue],
|
scope: hotkeyScope,
|
||||||
);
|
dependencies: [onShiftTab, inputValue],
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
export const getFieldInputInstanceId = ({
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
}: {
|
|
||||||
recordId: string;
|
|
||||||
fieldName: string;
|
|
||||||
}) => {
|
|
||||||
return `${recordId}-${fieldName}`;
|
|
||||||
};
|
|
||||||
@ -28,11 +28,14 @@ import {
|
|||||||
} from './RecordInlineCellContext';
|
} from './RecordInlineCellContext';
|
||||||
|
|
||||||
type RecordInlineCellProps = {
|
type RecordInlineCellProps = {
|
||||||
readonly?: boolean;
|
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
instanceIdPrefix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordInlineCell = ({ loading }: RecordInlineCellProps) => {
|
export const RecordInlineCell = ({
|
||||||
|
loading,
|
||||||
|
instanceIdPrefix,
|
||||||
|
}: RecordInlineCellProps) => {
|
||||||
const {
|
const {
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
recordId,
|
recordId,
|
||||||
@ -47,13 +50,28 @@ export const RecordInlineCell = ({ loading }: RecordInlineCellProps) => {
|
|||||||
|
|
||||||
const onOpenEditMode = onOpenEditModeFromContext
|
const onOpenEditMode = onOpenEditModeFromContext
|
||||||
? onOpenEditModeFromContext
|
? onOpenEditModeFromContext
|
||||||
: () => openFieldInput({ fieldDefinition, recordId });
|
: () =>
|
||||||
|
openFieldInput({
|
||||||
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
prefix: instanceIdPrefix,
|
||||||
|
});
|
||||||
|
|
||||||
const onCloseEditMode = useCallback(() => {
|
const onCloseEditMode = useCallback(() => {
|
||||||
onCloseEditModeFromContext
|
onCloseEditModeFromContext
|
||||||
? onCloseEditModeFromContext()
|
? onCloseEditModeFromContext()
|
||||||
: closeFieldInput({ fieldDefinition, recordId });
|
: closeFieldInput({
|
||||||
}, [onCloseEditModeFromContext, closeFieldInput, fieldDefinition, recordId]);
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
prefix: instanceIdPrefix,
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
onCloseEditModeFromContext,
|
||||||
|
closeFieldInput,
|
||||||
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
instanceIdPrefix,
|
||||||
|
]);
|
||||||
|
|
||||||
const buttonIcon = useGetButtonIcon();
|
const buttonIcon = useGetButtonIcon();
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useContext } from 'react';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
|
import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
|
||||||
import { RecordInlineCellValue } from '@/object-record/record-inline-cell/components/RecordInlineCellValue';
|
import { RecordInlineCellValue } from '@/object-record/record-inline-cell/components/RecordInlineCellValue';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
|
||||||
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
|
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
|
||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||||
@ -123,10 +123,10 @@ export const RecordInlineCellContainer = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const labelId = `label-${getRecordFieldInputId(
|
const labelId = `label-${getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition?.metadata?.fieldName,
|
fieldName: fieldDefinition?.metadata?.fieldName,
|
||||||
)}`;
|
})}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInlineCellBaseContainer
|
<StyledInlineCellBaseContainer
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
|||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
@ -41,8 +40,6 @@ export const MultipleRecordPicker = ({
|
|||||||
componentInstanceId,
|
componentInstanceId,
|
||||||
focusId,
|
focusId,
|
||||||
}: MultipleRecordPickerProps) => {
|
}: MultipleRecordPickerProps) => {
|
||||||
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
|
|
||||||
|
|
||||||
const selectableListComponentInstanceId =
|
const selectableListComponentInstanceId =
|
||||||
getMultipleRecordPickerSelectableListId(componentInstanceId);
|
getMultipleRecordPickerSelectableListId(componentInstanceId);
|
||||||
|
|
||||||
@ -79,7 +76,6 @@ export const MultipleRecordPicker = ({
|
|||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
onSubmit?.();
|
onSubmit?.();
|
||||||
goBackToPreviousHotkeyScope();
|
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
resetState();
|
resetState();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { useRecordShowContainerActions } from '@/object-record/record-show/hooks
|
|||||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||||
import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection';
|
import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection';
|
||||||
import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection';
|
import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
||||||
import { useIsInRightDrawerOrThrow } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
|
import { useIsInRightDrawerOrThrow } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
@ -28,6 +28,8 @@ type FieldsCardProps = {
|
|||||||
objectRecordId: string;
|
objectRecordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const INPUT_ID_PREFIX = 'fields-card';
|
||||||
|
|
||||||
export const FieldsCard = ({
|
export const FieldsCard = ({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
objectRecordId,
|
objectRecordId,
|
||||||
@ -139,13 +141,13 @@ export const FieldsCard = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ActivityTargetsInlineCell
|
<ActivityTargetsInlineCell
|
||||||
componentInstanceId={getRecordFieldInputId(
|
componentInstanceId={getRecordFieldInputInstanceId({
|
||||||
objectRecordId,
|
recordId: objectRecordId,
|
||||||
fieldMetadataItem.name,
|
fieldName: fieldMetadataItem.name,
|
||||||
isInRightDrawer
|
prefix: isInRightDrawer
|
||||||
? 'right-drawer-fields-card'
|
? 'right-drawer-fields-card'
|
||||||
: 'fields-card',
|
: 'fields-card',
|
||||||
)}
|
})}
|
||||||
activityObjectNameSingular={
|
activityObjectNameSingular={
|
||||||
objectNameSingular as
|
objectNameSingular as
|
||||||
| CoreObjectNameSingular.Note
|
| CoreObjectNameSingular.Note
|
||||||
@ -185,14 +187,17 @@ export const FieldsCard = ({
|
|||||||
>
|
>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
objectRecordId,
|
recordId: objectRecordId,
|
||||||
fieldMetadataItem.name,
|
fieldName: fieldMetadataItem.name,
|
||||||
'fields-card',
|
prefix: INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordInlineCell loading={recordLoading} />
|
<RecordInlineCell
|
||||||
|
loading={recordLoading}
|
||||||
|
instanceIdPrefix={INPUT_ID_PREFIX}
|
||||||
|
/>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import { RecordDetailRecordsListItem } from '@/object-record/record-show/record-
|
|||||||
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/getForeignKeyNameFromRelationFieldName';
|
import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/getForeignKeyNameFromRelationFieldName';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
@ -320,14 +320,14 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
>
|
>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordFieldInputId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
relationRecord.id,
|
recordId: relationRecord.id,
|
||||||
fieldMetadataItem.name,
|
fieldName: fieldMetadataItem.name,
|
||||||
'record-detail',
|
prefix: 'record-detail',
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordInlineCell />
|
<RecordInlineCell instanceIdPrefix="record-detail" />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const RECORD_TABLE_CELL_INPUT_ID_PREFIX = 'record-table-cell';
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||||
import { useBuildRecordInputFromFilters } from '@/object-record/record-table/hooks/useBuildRecordInputFromFilters';
|
import { useBuildRecordInputFromFilters } from '@/object-record/record-table/hooks/useBuildRecordInputFromFilters';
|
||||||
@ -10,6 +11,7 @@ import { canOpenObjectInSidePanel } from '@/object-record/utils/canOpenObjectInS
|
|||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||||
|
|
||||||
@ -58,11 +60,16 @@ export const useCreateNewIndexRecord = ({
|
|||||||
isNewRecord: true,
|
isNewRecord: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
openRecordTitleCell({
|
const labelIdentifierFieldMetadataItem =
|
||||||
recordId,
|
getLabelIdentifierFieldMetadataItem(objectMetadataItem);
|
||||||
fieldMetadataId: objectMetadataItem.labelIdentifierFieldMetadataId,
|
|
||||||
containerType: RecordTitleCellContainerType.ShowPage,
|
if (isDefined(labelIdentifierFieldMetadataItem)) {
|
||||||
});
|
openRecordTitleCell({
|
||||||
|
recordId,
|
||||||
|
fieldName: labelIdentifierFieldMetadataItem.name,
|
||||||
|
containerType: RecordTitleCellContainerType.ShowPage,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(AppPath.RecordShowPage, {
|
navigate(AppPath.RecordShowPage, {
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
@ -74,8 +81,7 @@ export const useCreateNewIndexRecord = ({
|
|||||||
buildRecordInputFromFilters,
|
buildRecordInputFromFilters,
|
||||||
createOneRecord,
|
createOneRecord,
|
||||||
navigate,
|
navigate,
|
||||||
objectMetadataItem.labelIdentifierFieldMetadataId,
|
objectMetadataItem,
|
||||||
objectMetadataItem.nameSingular,
|
|
||||||
openRecordInCommandMenu,
|
openRecordInCommandMenu,
|
||||||
openRecordTitleCell,
|
openRecordTitleCell,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { RecordTableCellFieldContextGeneric } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric';
|
import { RecordTableCellFieldContextGeneric } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric';
|
||||||
import { RecordTableCellFieldContextLabelIdentifier } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier';
|
import { RecordTableCellFieldContextLabelIdentifier } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { ReactNode, useContext } from 'react';
|
import { ReactNode, useContext } from 'react';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
@ -24,11 +25,11 @@ export const RecordTableCellFieldContextWrapper = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instanceId = getRecordFieldInputId(
|
const instanceId = getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
columnDefinition.metadata.fieldName,
|
fieldName: columnDefinition.metadata.fieldName,
|
||||||
'record-table-cell',
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
);
|
});
|
||||||
|
|
||||||
const isLabelIdentifier = isLabelIdentifierField({
|
const isLabelIdentifier = isLabelIdentifierField({
|
||||||
fieldMetadataItem: {
|
fieldMetadataItem: {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldVal
|
|||||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId';
|
import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId';
|
||||||
|
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||||
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
||||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
@ -20,7 +21,7 @@ import { viewableRecordNameSingularState } from '@/object-record/record-right-dr
|
|||||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||||
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
|
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
|
||||||
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
|
|
||||||
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||||
@ -166,6 +167,7 @@ export const useOpenRecordTableCellV2 = (recordTableId: string) => {
|
|||||||
openFieldInput({
|
openFieldInput({
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
recordId,
|
recordId,
|
||||||
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
});
|
});
|
||||||
|
|
||||||
setCurrentTableCellInEditModePosition(cellPosition);
|
setCurrentTableCellInEditModePosition(cellPosition);
|
||||||
@ -174,11 +176,11 @@ export const useOpenRecordTableCellV2 = (recordTableId: string) => {
|
|||||||
value: initialValue,
|
value: initialValue,
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
fieldComponentInstanceId: getRecordFieldInputId(
|
fieldComponentInstanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
'record-table-cell',
|
prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX,
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
toggleClickOutside(false);
|
toggleClickOutside(false);
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { RecordTitleCellFieldDisplay } from '@/object-record/record-title-cell/c
|
|||||||
import { RecordTitleCellFieldInput } from '@/object-record/record-title-cell/components/RecordTitleCellFieldInput';
|
import { RecordTitleCellFieldInput } from '@/object-record/record-title-cell/components/RecordTitleCellFieldInput';
|
||||||
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
||||||
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
||||||
import { getRecordTitleCellId } from '@/object-record/record-title-cell/utils/getRecordTitleCellId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
|
||||||
type RecordTitleCellProps = {
|
type RecordTitleCellProps = {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
@ -37,54 +37,46 @@ export const RecordTitleCell = ({
|
|||||||
|
|
||||||
const { closeRecordTitleCell } = useRecordTitleCell();
|
const { closeRecordTitleCell } = useRecordTitleCell();
|
||||||
|
|
||||||
const handleEnter: FieldInputEvent = (persistField) => {
|
const closeCell = () => {
|
||||||
closeRecordTitleCell({
|
closeRecordTitleCell({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId: fieldDefinition?.fieldMetadataId,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
containerType,
|
containerType,
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEnter: FieldInputEvent = (persistField) => {
|
||||||
|
closeCell();
|
||||||
persistField();
|
persistField();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEscape: FieldInputEvent = (persistField) => {
|
const handleEscape = () => {
|
||||||
closeRecordTitleCell({
|
closeCell();
|
||||||
recordId,
|
|
||||||
fieldMetadataId: fieldDefinition?.fieldMetadataId,
|
|
||||||
containerType,
|
|
||||||
});
|
|
||||||
persistField();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTab: FieldInputEvent = (persistField) => {
|
const handleTab: FieldInputEvent = (persistField) => {
|
||||||
closeRecordTitleCell({
|
closeCell();
|
||||||
recordId,
|
|
||||||
fieldMetadataId: fieldDefinition?.fieldMetadataId,
|
|
||||||
containerType,
|
|
||||||
});
|
|
||||||
persistField();
|
persistField();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShiftTab: FieldInputEvent = (persistField) => {
|
const handleShiftTab: FieldInputEvent = (persistField) => {
|
||||||
closeRecordTitleCell({
|
closeCell();
|
||||||
recordId,
|
|
||||||
fieldMetadataId: fieldDefinition?.fieldMetadataId,
|
|
||||||
containerType,
|
|
||||||
});
|
|
||||||
persistField();
|
persistField();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickOutside: FieldInputClickOutsideEvent = (persistField) => {
|
const handleClickOutside: FieldInputClickOutsideEvent = (persistField) => {
|
||||||
closeRecordTitleCell({
|
closeCell();
|
||||||
recordId,
|
|
||||||
fieldMetadataId: fieldDefinition?.fieldMetadataId,
|
|
||||||
containerType,
|
|
||||||
});
|
|
||||||
persistField();
|
persistField();
|
||||||
};
|
};
|
||||||
|
|
||||||
const recordTitleCellContextValue: RecordTitleCellContextProps = {
|
const recordTitleCellContextValue: RecordTitleCellContextProps = {
|
||||||
editModeContent: (
|
editModeContent: (
|
||||||
<RecordTitleCellFieldInput
|
<RecordTitleCellFieldInput
|
||||||
|
instanceId={getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix: containerType,
|
||||||
|
})}
|
||||||
onEnter={handleEnter}
|
onEnter={handleEnter}
|
||||||
onEscape={handleEscape}
|
onEscape={handleEscape}
|
||||||
onTab={handleTab}
|
onTab={handleTab}
|
||||||
@ -93,7 +85,9 @@ export const RecordTitleCell = ({
|
|||||||
sizeVariant={sizeVariant}
|
sizeVariant={sizeVariant}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
displayModeContent: <RecordTitleCellFieldDisplay />,
|
displayModeContent: (
|
||||||
|
<RecordTitleCellFieldDisplay containerType={containerType} />
|
||||||
|
),
|
||||||
editModeContentOnly: isFieldInputOnly,
|
editModeContentOnly: isFieldInputOnly,
|
||||||
loading: loading,
|
loading: loading,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
@ -103,11 +97,11 @@ export const RecordTitleCell = ({
|
|||||||
return (
|
return (
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRecordTitleCellId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition?.fieldMetadataId,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldFocusContextProvider>
|
<FieldFocusContextProvider>
|
||||||
|
|||||||
@ -3,9 +3,14 @@ import { isFieldFullName } from '@/object-record/record-field/types/guards/isFie
|
|||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||||
import { RecordTitleCellSingleTextDisplayMode } from '@/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay';
|
import { RecordTitleCellSingleTextDisplayMode } from '@/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay';
|
||||||
import { RecordTitleFullNameFieldDisplay } from '@/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay';
|
import { RecordTitleFullNameFieldDisplay } from '@/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay';
|
||||||
|
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
export const RecordTitleCellFieldDisplay = () => {
|
export const RecordTitleCellFieldDisplay = ({
|
||||||
|
containerType,
|
||||||
|
}: {
|
||||||
|
containerType: RecordTitleCellContainerType;
|
||||||
|
}) => {
|
||||||
const { fieldDefinition } = useContext(FieldContext);
|
const { fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
if (!isFieldText(fieldDefinition) && !isFieldFullName(fieldDefinition)) {
|
if (!isFieldText(fieldDefinition) && !isFieldFullName(fieldDefinition)) {
|
||||||
@ -15,9 +20,9 @@ export const RecordTitleCellFieldDisplay = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isFieldText(fieldDefinition) ? (
|
{isFieldText(fieldDefinition) ? (
|
||||||
<RecordTitleCellSingleTextDisplayMode />
|
<RecordTitleCellSingleTextDisplayMode containerType={containerType} />
|
||||||
) : isFieldFullName(fieldDefinition) ? (
|
) : isFieldFullName(fieldDefinition) ? (
|
||||||
<RecordTitleFullNameFieldDisplay />
|
<RecordTitleFullNameFieldDisplay containerType={containerType} />
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { RecordTitleFullNameFieldInput } from '@/object-record/record-title-cell
|
|||||||
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
||||||
|
|
||||||
type RecordTitleCellFieldInputProps = {
|
type RecordTitleCellFieldInputProps = {
|
||||||
|
instanceId: string;
|
||||||
onClickOutside?: (
|
onClickOutside?: (
|
||||||
persist: () => void,
|
persist: () => void,
|
||||||
event: MouseEvent | TouchEvent,
|
event: MouseEvent | TouchEvent,
|
||||||
@ -21,6 +22,7 @@ type RecordTitleCellFieldInputProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTitleCellFieldInput = ({
|
export const RecordTitleCellFieldInput = ({
|
||||||
|
instanceId,
|
||||||
sizeVariant,
|
sizeVariant,
|
||||||
onEnter,
|
onEnter,
|
||||||
onEscape,
|
onEscape,
|
||||||
@ -38,6 +40,7 @@ export const RecordTitleCellFieldInput = ({
|
|||||||
<>
|
<>
|
||||||
{isFieldText(fieldDefinition) ? (
|
{isFieldText(fieldDefinition) ? (
|
||||||
<RecordTitleCellTextFieldInput
|
<RecordTitleCellTextFieldInput
|
||||||
|
instanceId={instanceId}
|
||||||
onEnter={onEnter}
|
onEnter={onEnter}
|
||||||
onEscape={onEscape}
|
onEscape={onEscape}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { RecordTitleCellContext } from '@/object-record/record-title-cell/components/RecordTitleCellContext';
|
|
||||||
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
||||||
|
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
||||||
import { Theme, withTheme } from '@emotion/react';
|
import { Theme, withTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
@ -30,7 +30,11 @@ const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>`
|
|||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export const RecordTitleCellSingleTextDisplayMode = () => {
|
export const RecordTitleCellSingleTextDisplayMode = ({
|
||||||
|
containerType,
|
||||||
|
}: {
|
||||||
|
containerType: RecordTitleCellContainerType;
|
||||||
|
}) => {
|
||||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
||||||
@ -40,14 +44,12 @@ export const RecordTitleCellSingleTextDisplayMode = () => {
|
|||||||
|
|
||||||
const { openRecordTitleCell } = useRecordTitleCell();
|
const { openRecordTitleCell } = useRecordTitleCell();
|
||||||
|
|
||||||
const { containerType } = useContext(RecordTitleCellContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDiv
|
<StyledDiv
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openRecordTitleCell({
|
openRecordTitleCell({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId: fieldDefinition.fieldMetadataId,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
containerType,
|
containerType,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { isDefined } from 'twenty-shared/utils';
|
|||||||
import { turnIntoUndefinedIfWhitespacesOnly } from '~/utils/string/turnIntoUndefinedIfWhitespacesOnly';
|
import { turnIntoUndefinedIfWhitespacesOnly } from '~/utils/string/turnIntoUndefinedIfWhitespacesOnly';
|
||||||
|
|
||||||
type RecordTitleCellTextFieldInputProps = {
|
type RecordTitleCellTextFieldInputProps = {
|
||||||
|
instanceId: string;
|
||||||
onClickOutside?: FieldInputClickOutsideEvent;
|
onClickOutside?: FieldInputClickOutsideEvent;
|
||||||
onEnter?: FieldInputEvent;
|
onEnter?: FieldInputEvent;
|
||||||
onEscape?: FieldInputEvent;
|
onEscape?: FieldInputEvent;
|
||||||
@ -21,6 +22,7 @@ type RecordTitleCellTextFieldInputProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTitleCellTextFieldInput = ({
|
export const RecordTitleCellTextFieldInput = ({
|
||||||
|
instanceId,
|
||||||
sizeVariant,
|
sizeVariant,
|
||||||
onEnter,
|
onEnter,
|
||||||
onEscape,
|
onEscape,
|
||||||
@ -40,6 +42,7 @@ export const RecordTitleCellTextFieldInput = ({
|
|||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
|
|
||||||
useRegisterInputEvents<string>({
|
useRegisterInputEvents<string>({
|
||||||
|
focusId: instanceId,
|
||||||
inputRef: wrapperRef,
|
inputRef: wrapperRef,
|
||||||
inputValue: draftValue ?? '',
|
inputValue: draftValue ?? '',
|
||||||
onEnter: (inputValue) => {
|
onEnter: (inputValue) => {
|
||||||
|
|||||||
@ -2,13 +2,15 @@ import styled from '@emotion/styled';
|
|||||||
import { ClipboardEvent, useEffect, useRef, useState } from 'react';
|
import { ClipboardEvent, useEffect, useRef, useState } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText';
|
import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText';
|
||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { splitFullName } from '~/utils/format/spiltFullName';
|
import { splitFullName } from '~/utils/format/spiltFullName';
|
||||||
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -82,33 +84,39 @@ export const RecordTitleDoubleTextInput = ({
|
|||||||
|
|
||||||
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
|
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
|
||||||
|
|
||||||
useScopedHotkeys(
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
Key.Enter,
|
RecordFieldComponentInstanceContext,
|
||||||
() => {
|
);
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.Enter],
|
||||||
|
callback: () => {
|
||||||
onEnter({
|
onEnter({
|
||||||
firstValue: firstInternalValue,
|
firstValue: firstInternalValue,
|
||||||
secondValue: secondInternalValue,
|
secondValue: secondInternalValue,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[onEnter, firstInternalValue, secondInternalValue],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [onEnter, firstInternalValue, secondInternalValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
[Key.Escape],
|
keys: [Key.Escape],
|
||||||
() => {
|
callback: () => {
|
||||||
onEscape({
|
onEscape({
|
||||||
firstValue: firstInternalValue,
|
firstValue: firstInternalValue,
|
||||||
secondValue: secondInternalValue,
|
secondValue: secondInternalValue,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[onEscape, firstInternalValue, secondInternalValue],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [onEscape, firstInternalValue, secondInternalValue],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'tab',
|
keys: ['tab'],
|
||||||
() => {
|
callback: () => {
|
||||||
if (focusPosition === 'left') {
|
if (focusPosition === 'left') {
|
||||||
setFocusPosition('right');
|
setFocusPosition('right');
|
||||||
secondValueInputRef.current?.focus();
|
secondValueInputRef.current?.focus();
|
||||||
@ -119,13 +127,19 @@ export const RecordTitleDoubleTextInput = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[onTab, firstInternalValue, secondInternalValue, focusPosition],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [
|
||||||
|
onTab,
|
||||||
|
firstInternalValue,
|
||||||
|
secondInternalValue,
|
||||||
|
focusPosition,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
'shift+tab',
|
keys: ['shift+tab'],
|
||||||
() => {
|
callback: () => {
|
||||||
if (focusPosition === 'right') {
|
if (focusPosition === 'right') {
|
||||||
setFocusPosition('left');
|
setFocusPosition('left');
|
||||||
firstValueInputRef.current?.focus();
|
firstValueInputRef.current?.focus();
|
||||||
@ -136,9 +150,15 @@ export const RecordTitleDoubleTextInput = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hotkeyScope,
|
scope: hotkeyScope,
|
||||||
[onShiftTab, firstInternalValue, secondInternalValue, focusPosition],
|
focusId: instanceId,
|
||||||
);
|
dependencies: [
|
||||||
|
onShiftTab,
|
||||||
|
firstInternalValue,
|
||||||
|
secondInternalValue,
|
||||||
|
focusPosition,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
refs: [containerRef],
|
refs: [containerRef],
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { useFullNameFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useFullNameFieldDisplay';
|
import { useFullNameFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useFullNameFieldDisplay';
|
||||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
||||||
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
||||||
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { Theme, withTheme } from '@emotion/react';
|
import { Theme, withTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
@ -33,8 +35,12 @@ const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>`
|
|||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export const RecordTitleFullNameFieldDisplay = () => {
|
export const RecordTitleFullNameFieldDisplay = ({
|
||||||
const { fieldDefinition } = useContext(FieldContext);
|
containerType,
|
||||||
|
}: {
|
||||||
|
containerType: string;
|
||||||
|
}) => {
|
||||||
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
const { openInlineCell } = useInlineCell();
|
const { openInlineCell } = useInlineCell();
|
||||||
|
|
||||||
@ -45,14 +51,29 @@ export const RecordTitleFullNameFieldDisplay = () => {
|
|||||||
.join(' ')
|
.join(' ')
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
|
||||||
|
const recordTitleCellId = getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
prefix: containerType,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDiv
|
<StyledDiv
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setHotkeyScopeAndMemorizePreviousScope({
|
pushFocusItemToFocusStack({
|
||||||
scope: TitleInputHotkeyScope.TitleInput,
|
focusId: recordTitleCellId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
|
instanceId: recordTitleCellId,
|
||||||
|
},
|
||||||
|
hotkeyScope: {
|
||||||
|
scope: TitleInputHotkeyScope.TitleInput,
|
||||||
|
},
|
||||||
memoizeKey: INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY,
|
memoizeKey: INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY,
|
||||||
});
|
});
|
||||||
|
|
||||||
openInlineCell();
|
openInlineCell();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s
|
|||||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
||||||
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
|
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
|
||||||
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
||||||
import { getRecordTitleCellId } from '@/object-record/record-title-cell/utils/getRecordTitleCellId';
|
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
||||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
@ -25,26 +25,30 @@ export const useRecordTitleCell = () => {
|
|||||||
({ set }) =>
|
({ set }) =>
|
||||||
({
|
({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
containerType,
|
||||||
}: {
|
}: {
|
||||||
recordId: string;
|
recordId: string;
|
||||||
fieldMetadataId: string;
|
fieldName: string;
|
||||||
containerType: RecordTitleCellContainerType;
|
containerType: RecordTitleCellContainerType;
|
||||||
}) => {
|
}) => {
|
||||||
set(
|
set(
|
||||||
isInlineCellInEditModeScopedState(
|
isInlineCellInEditModeScopedState(
|
||||||
getRecordTitleCellId(recordId, fieldMetadataId, containerType),
|
getRecordFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName,
|
||||||
|
prefix: containerType,
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
removeFocusItemFromFocusStackById({
|
removeFocusItemFromFocusStackById({
|
||||||
focusId: getRecordTitleCellId(
|
focusId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
goBackToPreviousDropdownFocusId();
|
goBackToPreviousDropdownFocusId();
|
||||||
@ -58,47 +62,47 @@ export const useRecordTitleCell = () => {
|
|||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
({
|
({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
containerType,
|
||||||
customEditHotkeyScopeForField,
|
customEditHotkeyScopeForField,
|
||||||
}: {
|
}: {
|
||||||
recordId: string;
|
recordId: string;
|
||||||
fieldMetadataId: string;
|
fieldName: string;
|
||||||
containerType: RecordTitleCellContainerType;
|
containerType: RecordTitleCellContainerType;
|
||||||
customEditHotkeyScopeForField?: HotkeyScope;
|
customEditHotkeyScopeForField?: HotkeyScope;
|
||||||
}) => {
|
}) => {
|
||||||
if (isDefined(customEditHotkeyScopeForField)) {
|
if (isDefined(customEditHotkeyScopeForField)) {
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getRecordTitleCellId(
|
focusId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.OPENED_FIELD_INPUT,
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
instanceId: getRecordTitleCellId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
hotkeyScope: customEditHotkeyScopeForField,
|
hotkeyScope: customEditHotkeyScopeForField,
|
||||||
memoizeKey: INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY,
|
memoizeKey: INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getRecordTitleCellId(
|
focusId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.OPENED_FIELD_INPUT,
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
instanceId: getRecordTitleCellId(
|
instanceId: getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
hotkeyScope: {
|
hotkeyScope: {
|
||||||
scope: TitleInputHotkeyScope.TitleInput,
|
scope: TitleInputHotkeyScope.TitleInput,
|
||||||
@ -107,11 +111,11 @@ export const useRecordTitleCell = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const recordTitleCellId = getRecordTitleCellId(
|
const recordTitleCellId = getRecordFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldMetadataId,
|
fieldName,
|
||||||
containerType,
|
prefix: containerType,
|
||||||
);
|
});
|
||||||
set(isInlineCellInEditModeScopedState(recordTitleCellId), true);
|
set(isInlineCellInEditModeScopedState(recordTitleCellId), true);
|
||||||
|
|
||||||
const recordIndexFieldDefinitions = snapshot
|
const recordIndexFieldDefinitions = snapshot
|
||||||
@ -119,7 +123,7 @@ export const useRecordTitleCell = () => {
|
|||||||
.getValue();
|
.getValue();
|
||||||
|
|
||||||
const fieldDefinition = recordIndexFieldDefinitions.find(
|
const fieldDefinition = recordIndexFieldDefinitions.find(
|
||||||
(field) => field.fieldMetadataId === fieldMetadataId,
|
(field) => field.metadata.fieldName === fieldName,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!fieldDefinition) {
|
if (!fieldDefinition) {
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
|
||||||
|
|
||||||
export const getRecordTitleCellId = (
|
|
||||||
recordId: string,
|
|
||||||
fieldMetadataId: string,
|
|
||||||
containerType: RecordTitleCellContainerType,
|
|
||||||
) => {
|
|
||||||
return `${recordId}-${fieldMetadataId}-${containerType}`;
|
|
||||||
};
|
|
||||||
@ -1,9 +1,14 @@
|
|||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
export const getRecordFieldInputId = (
|
|
||||||
recordId: string,
|
export const getRecordFieldInputInstanceId = ({
|
||||||
fieldName?: string,
|
recordId,
|
||||||
prefix?: string,
|
fieldName,
|
||||||
): string => {
|
prefix,
|
||||||
|
}: {
|
||||||
|
recordId: string;
|
||||||
|
fieldName?: string;
|
||||||
|
prefix?: string;
|
||||||
|
}): string => {
|
||||||
if (isDefined(prefix)) {
|
if (isDefined(prefix)) {
|
||||||
return `${prefix}-${recordId}-${fieldName}`;
|
return `${prefix}-${recordId}-${fieldName}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,6 +95,7 @@ export const SettingsAccountsBlocklistInput = ({
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="settings-accounts-blocklist-input"
|
||||||
placeholder="eddy@gmail.com, @apple.com"
|
placeholder="eddy@gmail.com, @apple.com"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ export const SetttingsAccountsImapConnectionForm = ({
|
|||||||
defaultValue={defaultValues?.handle}
|
defaultValue={defaultValues?.handle}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="email-address-imap-connection-form"
|
||||||
label={t`Email Address`}
|
label={t`Email Address`}
|
||||||
placeholder={t`john.doe@example.com`}
|
placeholder={t`john.doe@example.com`}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
@ -58,6 +59,7 @@ export const SetttingsAccountsImapConnectionForm = ({
|
|||||||
defaultValue={defaultValues?.host}
|
defaultValue={defaultValues?.host}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="host-imap-connection-form"
|
||||||
label={t`IMAP Server`}
|
label={t`IMAP Server`}
|
||||||
placeholder={t`imap.example.com`}
|
placeholder={t`imap.example.com`}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
@ -72,6 +74,7 @@ export const SetttingsAccountsImapConnectionForm = ({
|
|||||||
defaultValue={defaultValues?.port ?? 993}
|
defaultValue={defaultValues?.port ?? 993}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="port-imap-connection-form"
|
||||||
label={t`IMAP Port`}
|
label={t`IMAP Port`}
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={t`993`}
|
placeholder={t`993`}
|
||||||
@ -104,6 +107,7 @@ export const SetttingsAccountsImapConnectionForm = ({
|
|||||||
defaultValue={defaultValues?.password}
|
defaultValue={defaultValues?.password}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="password-imap-connection-form"
|
||||||
label={t`Password`}
|
label={t`Password`}
|
||||||
placeholder={t`••••••••`}
|
placeholder={t`••••••••`}
|
||||||
type="password"
|
type="password"
|
||||||
|
|||||||
@ -156,6 +156,7 @@ export const SettingsAdminGeneral = () => {
|
|||||||
|
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="admin-user-lookup"
|
||||||
value={userIdentifier}
|
value={userIdentifier}
|
||||||
onChange={setUserIdentifier}
|
onChange={setUserIdentifier}
|
||||||
onInputEnter={handleSearch}
|
onInputEnter={handleSearch}
|
||||||
|
|||||||
@ -60,6 +60,8 @@ export const ConfigVariableDatabaseInput = ({
|
|||||||
onChange(newValues);
|
onChange(newValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const jsonArrayTextAreaId = `${label}-json-array`;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ConfigVariableType.BOOLEAN:
|
case ConfigVariableType.BOOLEAN:
|
||||||
return (
|
return (
|
||||||
@ -134,6 +136,7 @@ export const ConfigVariableDatabaseInput = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={jsonArrayTextAreaId}
|
||||||
label={label}
|
label={label}
|
||||||
value={
|
value={
|
||||||
Array.isArray(value)
|
Array.isArray(value)
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const ConfigVariableSearchInput = ({
|
|||||||
}: ConfigVariableSearchInputProps) => {
|
}: ConfigVariableSearchInputProps) => {
|
||||||
return (
|
return (
|
||||||
<StyledSearchInput
|
<StyledSearchInput
|
||||||
|
instanceId="config-variable-search"
|
||||||
placeholder={t`Search config variables`}
|
placeholder={t`Search config variables`}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { castAsNumberOrNull } from '~/utils/cast-as-number-or-null';
|
|
||||||
import { IconButton } from 'twenty-ui/input';
|
|
||||||
import { IconMinus, IconPlus } from 'twenty-ui/display';
|
import { IconMinus, IconPlus } from 'twenty-ui/display';
|
||||||
|
import { IconButton } from 'twenty-ui/input';
|
||||||
|
import { castAsNumberOrNull } from '~/utils/cast-as-number-or-null';
|
||||||
|
|
||||||
type SettingsCounterProps = {
|
type SettingsCounterProps = {
|
||||||
value: number;
|
value: number;
|
||||||
@ -77,6 +77,7 @@ export const SettingsCounter = ({
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
<StyledTextInput
|
<StyledTextInput
|
||||||
|
instanceId="settings-counter-input"
|
||||||
name="counter"
|
name="counter"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={value.toString()}
|
value={value.toString()}
|
||||||
|
|||||||
@ -29,6 +29,8 @@ export const SettingsDataModelFieldDescriptionForm = ({
|
|||||||
const { control } =
|
const { control } =
|
||||||
useFormContext<SettingsDataModelFieldDescriptionFormValues>();
|
useFormContext<SettingsDataModelFieldDescriptionFormValues>();
|
||||||
|
|
||||||
|
const descriptionTextAreaId = `${fieldMetadataItem?.id}-description`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Controller
|
<Controller
|
||||||
name="description"
|
name="description"
|
||||||
@ -36,6 +38,7 @@ export const SettingsDataModelFieldDescriptionForm = ({
|
|||||||
defaultValue={fieldMetadataItem?.description}
|
defaultValue={fieldMetadataItem?.description}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={descriptionTextAreaId}
|
||||||
placeholder={t`Write a description`}
|
placeholder={t`Write a description`}
|
||||||
minRows={4}
|
minRows={4}
|
||||||
value={value ?? undefined}
|
value={value ?? undefined}
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import { TextInput } from '@/ui/input/components/TextInput';
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
|
||||||
import {
|
import {
|
||||||
AppTooltip,
|
AppTooltip,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
@ -22,6 +21,7 @@ import {
|
|||||||
TooltipDelay,
|
TooltipDelay,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { Card } from 'twenty-ui/layout';
|
import { Card } from 'twenty-ui/layout';
|
||||||
|
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||||
|
|
||||||
export const settingsDataModelFieldIconLabelFormSchema = (
|
export const settingsDataModelFieldIconLabelFormSchema = (
|
||||||
existingOtherLabels: string[] = [],
|
existingOtherLabels: string[] = [],
|
||||||
@ -94,6 +94,9 @@ export const SettingsDataModelFieldIconLabelForm = ({
|
|||||||
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
|
const labelTextInputId = `${fieldMetadataItem?.id}-label`;
|
||||||
|
const nameTextInputId = `${fieldMetadataItem?.id}-name`;
|
||||||
|
|
||||||
const isLabelSyncedWithName =
|
const isLabelSyncedWithName =
|
||||||
watch('isLabelSyncedWithName') ??
|
watch('isLabelSyncedWithName') ??
|
||||||
(isDefined(fieldMetadataItem)
|
(isDefined(fieldMetadataItem)
|
||||||
@ -133,6 +136,7 @@ export const SettingsDataModelFieldIconLabelForm = ({
|
|||||||
defaultValue={fieldMetadataItem?.label}
|
defaultValue={fieldMetadataItem?.label}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={labelTextInputId}
|
||||||
placeholder={t`Employees`}
|
placeholder={t`Employees`}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
@ -167,6 +171,7 @@ export const SettingsDataModelFieldIconLabelForm = ({
|
|||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<>
|
<>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={nameTextInputId}
|
||||||
label={t`API Name`}
|
label={t`API Name`}
|
||||||
placeholder={t`employees`}
|
placeholder={t`employees`}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -108,6 +108,7 @@ export const SettingsObjectNewFieldSelector = ({
|
|||||||
{' '}
|
{' '}
|
||||||
<Section>
|
<Section>
|
||||||
<StyledSearchInput
|
<StyledSearchInput
|
||||||
|
instanceId="new-field-type-search"
|
||||||
LeftIcon={IconSearch}
|
LeftIcon={IconSearch}
|
||||||
placeholder={t`Search a type`}
|
placeholder={t`Search a type`}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
|
|||||||
@ -117,6 +117,7 @@ export const SettingsDataModelFieldDateForm = ({
|
|||||||
defaultValue={initialCustomUnicodeDateFormat}
|
defaultValue={initialCustomUnicodeDateFormat}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<StyledTextInput
|
<StyledTextInput
|
||||||
|
instanceId="custom-date-format-input"
|
||||||
placeholder={t`Format e.g. d-MMM-y (qqq''yy)`}
|
placeholder={t`Format e.g. d-MMM-y (qqq''yy)`}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(value) => onChange(value)}
|
onChange={(value) => onChange(value)}
|
||||||
|
|||||||
@ -187,6 +187,7 @@ export const SettingsDataModelFieldRelationForm = ({
|
|||||||
defaultValue={initialRelationFieldMetadataItem.label}
|
defaultValue={initialRelationFieldMetadataItem.label}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="relation-field-label"
|
||||||
disabled={disableFieldEdition}
|
disabled={disableFieldEdition}
|
||||||
placeholder={t`Field name`}
|
placeholder={t`Field name`}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -99,6 +99,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
|||||||
/>
|
/>
|
||||||
<AdvancedSettingsWrapper animationDimension="width" hideDot>
|
<AdvancedSettingsWrapper animationDimension="width" hideDot>
|
||||||
<StyledOptionInput
|
<StyledOptionInput
|
||||||
|
instanceId={`select-option-value-${option.id}`}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
onChange={(input) =>
|
onChange={(input) =>
|
||||||
onChange({
|
onChange({
|
||||||
@ -133,6 +134,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StyledOptionInput
|
<StyledOptionInput
|
||||||
|
instanceId={`select-option-label-${option.id}`}
|
||||||
value={option.label}
|
value={option.label}
|
||||||
onChange={(label) => {
|
onChange={(label) => {
|
||||||
const optionNameHasBeenEdited = !(
|
const optionNameHasBeenEdited = !(
|
||||||
|
|||||||
@ -123,6 +123,10 @@ export const SettingsDataModelObjectAboutForm = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const descriptionTextAreaId = `${objectMetadataItem?.id}-description`;
|
||||||
|
const labelSingularTextInputId = `${objectMetadataItem?.id}-label-singular`;
|
||||||
|
const labelPluralTextInputId = `${objectMetadataItem?.id}-label-plural`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledInputsContainer>
|
<StyledInputsContainer>
|
||||||
@ -150,6 +154,7 @@ export const SettingsDataModelObjectAboutForm = ({
|
|||||||
defaultValue={objectMetadataItem?.labelSingular ?? ''}
|
defaultValue={objectMetadataItem?.labelSingular ?? ''}
|
||||||
render={({ field: { onChange, value }, formState: { errors } }) => (
|
render={({ field: { onChange, value }, formState: { errors } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={labelSingularTextInputId}
|
||||||
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
|
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
|
||||||
noErrorHelper={true}
|
noErrorHelper={true}
|
||||||
error={errors.labelSingular?.message}
|
error={errors.labelSingular?.message}
|
||||||
@ -181,6 +186,7 @@ export const SettingsDataModelObjectAboutForm = ({
|
|||||||
defaultValue={objectMetadataItem?.labelPlural ?? ''}
|
defaultValue={objectMetadataItem?.labelPlural ?? ''}
|
||||||
render={({ field: { onChange, value }, formState: { errors } }) => (
|
render={({ field: { onChange, value }, formState: { errors } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={labelPluralTextInputId}
|
||||||
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
|
// TODO we should discuss on how to notify user about form validation schema issue, from now just displaying red borders
|
||||||
noErrorHelper={true}
|
noErrorHelper={true}
|
||||||
error={errors.labelPlural?.message}
|
error={errors.labelPlural?.message}
|
||||||
@ -210,6 +216,7 @@ export const SettingsDataModelObjectAboutForm = ({
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={descriptionTextAreaId}
|
||||||
placeholder={t`Write a description`}
|
placeholder={t`Write a description`}
|
||||||
minRows={4}
|
minRows={4}
|
||||||
value={value ?? undefined}
|
value={value ?? undefined}
|
||||||
@ -264,6 +271,7 @@ export const SettingsDataModelObjectAboutForm = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={`${objectMetadataItem?.id}-${fieldName}`}
|
||||||
label={label}
|
label={label}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const ApiKeyInput = ({ apiKey }: ApiKeyInputProps) => {
|
|||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLinkContainer>
|
<StyledLinkContainer>
|
||||||
<TextInput value={apiKey} fullWidth />
|
<TextInput instanceId="api-key-display" value={apiKey} fullWidth />
|
||||||
</StyledLinkContainer>
|
</StyledLinkContainer>
|
||||||
<Button
|
<Button
|
||||||
Icon={IconCopy}
|
Icon={IconCopy}
|
||||||
|
|||||||
@ -56,9 +56,12 @@ export const ApiKeyNameInput = ({
|
|||||||
return debouncedUpdate.cancel;
|
return debouncedUpdate.cancel;
|
||||||
}, [debouncedUpdate, apiKeyName]);
|
}, [debouncedUpdate, apiKeyName]);
|
||||||
|
|
||||||
|
const nameTextInputId = `${apiKeyId}-name`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledComboInputContainer>
|
<StyledComboInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={nameTextInputId}
|
||||||
placeholder="E.g. backoffice integration"
|
placeholder="E.g. backoffice integration"
|
||||||
onChange={onNameUpdate}
|
onChange={onNameUpdate}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -115,6 +115,10 @@ export const SettingsDevelopersWebhookForm = ({
|
|||||||
{ label: 'Deleted', value: 'deleted', Icon: IconTrash },
|
{ label: 'Deleted', value: 'deleted', Icon: IconTrash },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const descriptionTextAreaId = `${webhookId}-description`;
|
||||||
|
const targetUrlTextInputId = `${webhookId}-target-url`;
|
||||||
|
const secretTextInputId = `${webhookId}-secret`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
<FormProvider {...formConfig}>
|
<FormProvider {...formConfig}>
|
||||||
@ -156,6 +160,7 @@ export const SettingsDevelopersWebhookForm = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={targetUrlTextInputId}
|
||||||
placeholder={t`https://example.com/webhook`}
|
placeholder={t`https://example.com/webhook`}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
@ -177,6 +182,7 @@ export const SettingsDevelopersWebhookForm = ({
|
|||||||
control={formConfig.control}
|
control={formConfig.control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={descriptionTextAreaId}
|
||||||
placeholder={t`Write a description`}
|
placeholder={t`Write a description`}
|
||||||
minRows={4}
|
minRows={4}
|
||||||
value={value || ''}
|
value={value || ''}
|
||||||
@ -242,6 +248,7 @@ export const SettingsDevelopersWebhookForm = ({
|
|||||||
control={formConfig.control}
|
control={formConfig.control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={secretTextInputId}
|
||||||
placeholder={t`Secret (optional)`}
|
placeholder={t`Secret (optional)`}
|
||||||
value={value || ''}
|
value={value || ''}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Controller, useFormContext } from 'react-hook-form';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
@ -129,6 +129,7 @@ export const SettingsIntegrationDatabaseConnectionForm = ({
|
|||||||
render={({ field: { onChange, value } }) => {
|
render={({ field: { onChange, value } }) => {
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={`${databaseKey}-${name}`}
|
||||||
autoComplete="new-password" // Disable autocomplete
|
autoComplete="new-password" // Disable autocomplete
|
||||||
label={label}
|
label={label}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -117,6 +117,7 @@ export const PlaygroundSetupForm = () => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="playground-api-key"
|
||||||
label={t`API Key`}
|
label={t`API Key`}
|
||||||
placeholder="Enter your API key"
|
placeholder="Enter your API key"
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export const EmailField = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={`user-email-${currentUser?.id}`}
|
||||||
value={currentUser?.email}
|
value={currentUser?.email}
|
||||||
disabled
|
disabled
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
|
||||||
@ -109,9 +109,13 @@ export const NameFields = ({
|
|||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const firstNameTextInputId = `${currentWorkspaceMember?.id}-first-name`;
|
||||||
|
const lastNameTextInputId = `${currentWorkspaceMember?.id}-last-name`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledComboInputContainer>
|
<StyledComboInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={firstNameTextInputId}
|
||||||
label={t`First Name`}
|
label={t`First Name`}
|
||||||
value={firstName}
|
value={firstName}
|
||||||
onChange={setFirstName}
|
onChange={setFirstName}
|
||||||
@ -119,6 +123,7 @@ export const NameFields = ({
|
|||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={lastNameTextInputId}
|
||||||
label={t`Last Name`}
|
label={t`Last Name`}
|
||||||
value={lastName}
|
value={lastName}
|
||||||
onChange={setLastName}
|
onChange={setLastName}
|
||||||
|
|||||||
@ -210,6 +210,7 @@ export const SettingsRoleAssignment = ({
|
|||||||
/>
|
/>
|
||||||
<StyledSearchContainer>
|
<StyledSearchContainer>
|
||||||
<StyledSearchInput
|
<StyledSearchInput
|
||||||
|
instanceId="role-assignment-member-search"
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={handleSearchChange}
|
onChange={handleSearchChange}
|
||||||
placeholder={t`Search an assigned team member...`}
|
placeholder={t`Search an assigned team member...`}
|
||||||
|
|||||||
@ -125,6 +125,7 @@ export const SettingsRolePermissionsObjectLevelObjectPicker = ({
|
|||||||
<Section>
|
<Section>
|
||||||
<StyledSearchContainer>
|
<StyledSearchContainer>
|
||||||
<StyledSearchInput
|
<StyledSearchInput
|
||||||
|
instanceId="role-permissions-object-search"
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={handleSearchChange}
|
onChange={handleSearchChange}
|
||||||
placeholder={t`Search an object`}
|
placeholder={t`Search an object`}
|
||||||
|
|||||||
@ -42,6 +42,9 @@ export const SettingsRoleSettings = ({
|
|||||||
|
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
|
const descriptionTextAreaId = `${roleId}-description`;
|
||||||
|
const nameTextInputId = `${roleId}-name`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Section>
|
<Section>
|
||||||
@ -60,6 +63,7 @@ export const SettingsRoleSettings = ({
|
|||||||
/>
|
/>
|
||||||
</StyledInputContainer>
|
</StyledInputContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={nameTextInputId}
|
||||||
value={settingsDraftRole.label}
|
value={settingsDraftRole.label}
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={(value: string) => {
|
onChange={(value: string) => {
|
||||||
@ -73,6 +77,7 @@ export const SettingsRoleSettings = ({
|
|||||||
/>
|
/>
|
||||||
</StyledInputsContainer>
|
</StyledInputsContainer>
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={descriptionTextAreaId}
|
||||||
minRows={4}
|
minRows={4}
|
||||||
placeholder={t`Write a description`}
|
placeholder={t`Write a description`}
|
||||||
value={settingsDraftRole.description || ''}
|
value={settingsDraftRole.description || ''}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export const SettingsRoleLabelContainer = ({
|
|||||||
return (
|
return (
|
||||||
<StyledHeaderTitle>
|
<StyledHeaderTitle>
|
||||||
<TitleInput
|
<TitleInput
|
||||||
|
instanceId="role-label-input"
|
||||||
disabled={!settingsDraftRole.isEditable}
|
disabled={!settingsDraftRole.isEditable}
|
||||||
sizeVariant="md"
|
sizeVariant="md"
|
||||||
value={settingsDraftRole.label}
|
value={settingsDraftRole.label}
|
||||||
|
|||||||
@ -7,12 +7,12 @@ import { SettingsSSOSAMLForm } from '@/settings/security/components/SSO/Settings
|
|||||||
import { SettingSecurityNewSSOIdentityFormValues } from '@/settings/security/types/SSOIdentityProvider';
|
import { SettingSecurityNewSSOIdentityFormValues } from '@/settings/security/types/SSOIdentityProvider';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
import { ReactElement, useMemo } from 'react';
|
import { ReactElement, useMemo } from 'react';
|
||||||
import { Controller, useFormContext } from 'react-hook-form';
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
import { IdentityProviderType } from '~/generated/graphql';
|
|
||||||
import { t } from '@lingui/core/macro';
|
|
||||||
import { H2Title, IconComponent, IconKey } from 'twenty-ui/display';
|
import { H2Title, IconComponent, IconKey } from 'twenty-ui/display';
|
||||||
import { Section } from 'twenty-ui/layout';
|
import { Section } from 'twenty-ui/layout';
|
||||||
|
import { IdentityProviderType } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledInputsContainer = styled.div`
|
const StyledInputsContainer = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -88,6 +88,7 @@ export const SettingsSSOIdentitiesProvidersForm = () => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-identity-provider-name"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
label={t`Name`}
|
label={t`Name`}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export const SettingsSSOOIDCForm = () => {
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLinkContainer>
|
<StyledLinkContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-oidc-authorized-uri"
|
||||||
readOnly={true}
|
readOnly={true}
|
||||||
label={t`Authorized URI`}
|
label={t`Authorized URI`}
|
||||||
value={authorizedUrl}
|
value={authorizedUrl}
|
||||||
@ -81,6 +82,7 @@ export const SettingsSSOOIDCForm = () => {
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLinkContainer>
|
<StyledLinkContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-oidc-redirection-uri"
|
||||||
readOnly={true}
|
readOnly={true}
|
||||||
label={t`Redirection URI`}
|
label={t`Redirection URI`}
|
||||||
value={redirectionUrl}
|
value={redirectionUrl}
|
||||||
@ -118,6 +120,7 @@ export const SettingsSSOOIDCForm = () => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-oidc-client-id"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
label={t`Client ID`}
|
label={t`Client ID`}
|
||||||
value={value}
|
value={value}
|
||||||
@ -132,6 +135,7 @@ export const SettingsSSOOIDCForm = () => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-oidc-client-secret"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
type="password"
|
type="password"
|
||||||
label={t`Client Secret`}
|
label={t`Client Secret`}
|
||||||
@ -147,6 +151,7 @@ export const SettingsSSOOIDCForm = () => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-oidc-issuer"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
label={t`Issuer URI`}
|
label={t`Issuer URI`}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -169,6 +169,7 @@ export const SettingsSSOSAMLForm = () => {
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLinkContainer>
|
<StyledLinkContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-saml-acs-url"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
label="ACS Url"
|
label="ACS Url"
|
||||||
value={acsUrl}
|
value={acsUrl}
|
||||||
@ -196,6 +197,7 @@ export const SettingsSSOSAMLForm = () => {
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLinkContainer>
|
<StyledLinkContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId="sso-saml-entity-id"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
label="Entity ID"
|
label="Entity ID"
|
||||||
value={entityID}
|
value={entityID}
|
||||||
|
|||||||
@ -18,11 +18,15 @@ export const SettingsServerlessFunctionNewForm = ({
|
|||||||
formValues: ServerlessFunctionNewFormValues;
|
formValues: ServerlessFunctionNewFormValues;
|
||||||
onChange: (key: string) => (value: string) => void;
|
onChange: (key: string) => (value: string) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const descriptionTextAreaId = `${formValues.name}-description`;
|
||||||
|
const nameTextInputId = `${formValues.name}-name`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title="About" description="Name and set your function" />
|
<H2Title title="About" description="Name and set your function" />
|
||||||
<StyledInputsContainer>
|
<StyledInputsContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
instanceId={nameTextInputId}
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
fullWidth
|
fullWidth
|
||||||
autoFocusOnMount
|
autoFocusOnMount
|
||||||
@ -30,6 +34,7 @@ export const SettingsServerlessFunctionNewForm = ({
|
|||||||
onChange={onChange('name')}
|
onChange={onChange('name')}
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
|
textAreaId={descriptionTextAreaId}
|
||||||
placeholder="Description"
|
placeholder="Description"
|
||||||
minRows={4}
|
minRows={4}
|
||||||
value={formValues.description}
|
value={formValues.description}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user