Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Input fields to have expected behaviour in case of empty / only whitespaces string #6736

Merged
merged 31 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
97f2b7a
fix: empty string draftvalue doesn't resetting to undefined
Nabhag8848 Aug 26, 2024
77d1ead
fix: Api Keys Input Name Field
Nabhag8848 Aug 26, 2024
fabb543
fix: input fields to not have whitespaces only with new string util
Nabhag8848 Aug 26, 2024
37cefe1
fix: functions text input field and missing key in settings objects
Nabhag8848 Aug 26, 2024
76715b3
fix: disable email button when no correct email formats
Nabhag8848 Aug 26, 2024
e15c3ab
fix: text field to tackle with white spaces
Nabhag8848 Aug 26, 2024
820c207
chore: have convertToUndefinedForWhitespaces util
Nabhag8848 Aug 26, 2024
846e97d
fix: email field to handle whitespaces.
Nabhag8848 Aug 26, 2024
22ad211
fix: fullName field to handle whitespaces
Nabhag8848 Aug 26, 2024
3ba10ae
fix: fullName Field to not create object record with white spaces
Nabhag8848 Aug 26, 2024
b1560e2
fix: changes suggested by greptile
Nabhag8848 Aug 26, 2024
16ab362
fix: text input field with few changes
Nabhag8848 Aug 29, 2024
4478c81
fix: apikeys with few changes
Nabhag8848 Aug 29, 2024
89d053e
fix: core ui components instead
Nabhag8848 Aug 29, 2024
a271f90
fix: email field to remove redundant field
Nabhag8848 Aug 29, 2024
22d394c
fix: name field to not make changes with empty input
Nabhag8848 Aug 29, 2024
d7a084c
fix: Number Field
Nabhag8848 Aug 29, 2024
527db7a
fix: multiselect, select, selectinput, country
Nabhag8848 Aug 30, 2024
212e15d
fix: revert changes which doesn't makes sense
Nabhag8848 Aug 30, 2024
b23d0be
fix: FullNameFieldInput to handle whitespaces
Nabhag8848 Aug 30, 2024
02f5a71
fix: naming convention
Nabhag8848 Aug 30, 2024
bc29337
fix: changes suggested by greptile
Nabhag8848 Aug 30, 2024
917bc0c
fix: key missing issue and spaces issue in fullName
Nabhag8848 Aug 30, 2024
1d3bc65
Merge branch 'main' into fix/#6633-#6734
Nabhag8848 Aug 30, 2024
06f2db9
fix: paste of fullname to handle cases
Nabhag8848 Aug 30, 2024
5261ef3
Merge branch 'main' into fix/#6633-#6734
Nabhag8848 Aug 31, 2024
ad72c18
fix: more key errors
Nabhag8848 Aug 31, 2024
f6cce0d
Merge branch 'main' into fix/#6633-#6734
Nabhag8848 Sep 6, 2024
98e59c6
Merge branch 'main' into fix/#6633-#6734
lucasbordeau Sep 19, 2024
a0fb841
Fixed enter cannot save and zIndex of PageHeader
lucasbordeau Sep 19, 2024
8f129b5
Refactor
lucasbordeau Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleT
import { DoubleTextInput } from '@/ui/field/input/components/DoubleTextInput';
import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay';

import { usePersistField } from '../../../hooks/usePersistField';

import { FieldInputEvent } from './DateTimeFieldInput';

const FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS =
Expand All @@ -28,46 +26,61 @@ export const FullNameFieldInput = ({
onTab,
onShiftTab,
}: FullNameFieldInputProps) => {
const { hotkeyScope, draftValue, setDraftValue } = useFullNameField();
const { hotkeyScope, draftValue, setDraftValue, persistFullNameField } =
useFullNameField();

const persistField = usePersistField();
const isTrimmedFieldDoubleTextEmpty = (newDoubleText: FieldDoubleText) => {
const { firstValue, secondValue } = newDoubleText;
const totalLength = firstValue.trim().length + secondValue.trim().length;
return totalLength ? false : true;
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

const convertToFullName = (newDoubleText: FieldDoubleText) => {
return {
firstName: newDoubleText.firstValue,
lastName: newDoubleText.secondValue,
firstName: newDoubleText.firstValue.trim(),
lastName: newDoubleText.secondValue.trim(),
};
};

const getRequiredValuetoPersistFromDoubleText = (
newDoubleText: FieldDoubleText,
) => {
return isTrimmedFieldDoubleTextEmpty(newDoubleText)
? undefined
: convertToFullName(newDoubleText);
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

const handleEnter = (newDoubleText: FieldDoubleText) => {
onEnter?.(() => persistField(convertToFullName(newDoubleText)));
onEnter?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};

const handleEscape = (newDoubleText: FieldDoubleText) => {
onEscape?.(() => persistField(convertToFullName(newDoubleText)));
onEscape?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};

const handleClickOutside = (
event: MouseEvent | TouchEvent,
newDoubleText: FieldDoubleText,
) => {
onClickOutside?.(() => persistField(convertToFullName(newDoubleText)));
onClickOutside?.(() =>
persistFullNameField(convertToFullName(newDoubleText)),
);
};

const handleTab = (newDoubleText: FieldDoubleText) => {
onTab?.(() => persistField(convertToFullName(newDoubleText)));
onTab?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};

const handleShiftTab = (newDoubleText: FieldDoubleText) => {
onShiftTab?.(() => persistField(convertToFullName(newDoubleText)));
onShiftTab?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};

const handleChange = (newDoubleText: FieldDoubleText) => {
setDraftValue(convertToFullName(newDoubleText));
setDraftValue(getRequiredValuetoPersistFromDoubleText(newDoubleText));
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

const handlePaste = (newDoubleText: FieldDoubleText) => {
setDraftValue(convertToFullName(newDoubleText));
setDraftValue(getRequiredValuetoPersistFromDoubleText(newDoubleText));
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { MenuItemMultiSelectTag } from '@/ui/navigation/menu-item/components/Men
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from '~/utils/isDefined';
import { convertToEmptyStringForWhitespaces } from '~/utils/string/convertToEmptyStringForWhitespaces';

const StyledRelationPickerContainer = styled.div`
left: -1px;
Expand Down Expand Up @@ -107,7 +108,11 @@ export const MultiSelectFieldInput = ({
<DropdownMenu data-select-disable>
<DropdownMenuSearchInput
value={searchFilter}
onChange={(event) => setSearchFilter(event.currentTarget.value)}
onChange={(event) =>
setSearchFilter(
convertToEmptyStringForWhitespaces(event.currentTarget.value),
)
}
autoFocus
/>
<DropdownMenuSeparator />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const NumberFieldInput = ({
<TextInput
placeholder={fieldDefinition.metadata.placeHolder}
autoFocus
value={draftValue ?? ''}
value={draftValue?.toString() ?? ''}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TextAreaInput } from '@/ui/field/input/components/TextAreaInput';
import { usePersistField } from '../../../hooks/usePersistField';
import { useTextField } from '../../hooks/useTextField';

import { convertToUndefinedForWhitespaces } from '~/utils/string/convertToUndefinedForWhitespaces';
import { FieldInputEvent } from './DateTimeFieldInput';

export type TextFieldInputProps = {
Expand All @@ -25,32 +26,31 @@ export const TextFieldInput = ({
useTextField();

const persistField = usePersistField();

const handleEnter = (newText: string) => {
onEnter?.(() => persistField(newText));
onEnter?.(() => persistField(newText.trim()));
};

const handleEscape = (newText: string) => {
onEscape?.(() => persistField(newText));
onEscape?.(() => persistField(newText.trim()));
};

const handleClickOutside = (
event: MouseEvent | TouchEvent,
newText: string,
) => {
onClickOutside?.(() => persistField(newText));
onClickOutside?.(() => persistField(newText.trim()));
};

const handleTab = (newText: string) => {
onTab?.(() => persistField(newText));
onTab?.(() => persistField(newText.trim()));
};

const handleShiftTab = (newText: string) => {
onShiftTab?.(() => persistField(newText));
onShiftTab?.(() => persistField(newText.trim()));
};

const handleChange = (newText: string) => {
setDraftValue(newText);
setDraftValue(convertToUndefinedForWhitespaces(newText.trim()));
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@/object-record/record-field/types/FieldMetadata';

export type FieldTextDraftValue = string;
export type FieldNumberDraftValue = string;
export type FieldNumberDraftValue = number;
export type FieldDateTimeDraftValue = string;
export type FieldPhoneDraftValue = string;
export type FieldEmailDraftValue = string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useCallback, useEffect, useState } from 'react';
import styled from '@emotion/styled';
import { useCallback, useEffect, useState } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useDebouncedCallback } from 'use-debounce';

import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { TextInput } from '@/ui/input/components/TextInput';
import isEmpty from 'lodash.isempty';
import { useUpdateWorkspaceMutation } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
Expand Down Expand Up @@ -40,6 +41,7 @@ export const NameField = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedUpdate = useCallback(
useDebouncedCallback(async (name: string) => {
if (isEmpty(name)) return;
// update local recoil state when workspace name is updated
setCurrentWorkspace((currentValue) => {
if (currentValue === null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ export const DoubleTextInput = ({

const splittedName = name.split(' ');

onPaste?.({ firstValue: splittedName[0], secondValue: splittedName[1] });
onPaste?.({
firstValue: splittedName[0].trim(),
secondValue: splittedName[1].trim(),
});
};

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import styled from '@emotion/styled';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import styled from '@emotion/styled';
import { TEXT_INPUT_STYLE } from 'twenty-ui';

import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { isDefined } from '~/utils/isDefined';
import { convertToEmptyStringForWhitespaces } from '~/utils/string/convertToEmptyStringForWhitespaces';

export type TextAreaInputProps = {
disabled?: boolean;
Expand Down Expand Up @@ -67,10 +68,10 @@ export const TextAreaInput = ({
copyButton = true,
}: TextAreaInputProps) => {
const [internalText, setInternalText] = useState(value);

const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
setInternalText(event.target.value);
onChange?.(event.target.value);
const targetValue = convertToEmptyStringForWhitespaces(event.target.value);
setInternalText(targetValue);
onChange?.(targetValue);
};

const wrapperRef = useRef<HTMLTextAreaElement>(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { TEXT_INPUT_STYLE } from 'twenty-ui';

import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
Expand Down Expand Up @@ -44,12 +44,11 @@ export const TextInput = ({
const copyRef = useRef<HTMLDivElement>(null);

const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setInternalText(event.target.value);
onChange?.(event.target.value);
setInternalText(event.target.value.trim());
onChange?.(event.target.value.trim());
};
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved
useEffect(() => {
setInternalText(value);
setInternalText(value.trim());
}, [value]);
Nabhag8848 marked this conversation as resolved.
Show resolved Hide resolved

useRegisterInputEvents({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import styled from '@emotion/styled';
import { FocusEventHandler } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import styled from '@emotion/styled';

import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';

import { convertToEmptyStringForWhitespaces } from '~/utils/string/convertToEmptyStringForWhitespaces';
import { InputHotkeyScope } from '../types/InputHotkeyScope';

const MAX_ROWS = 5;
Expand Down Expand Up @@ -75,7 +76,9 @@ export const TextArea = ({
maxRows={MAX_ROWS}
minRows={computedMinRows}
value={value}
onChange={(event) => onChange?.(event.target.value)}
onChange={(event) =>
onChange?.(convertToEmptyStringForWhitespaces(event.target.value))
}
onFocus={handleFocus}
onBlur={handleBlur}
disabled={disabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from 'react';
import { IconComponent, IconEye, IconEyeOff } from 'twenty-ui';
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
import { convertToEmptyStringForWhitespaces } from '~/utils/string/convertToEmptyStringForWhitespaces';

const StyledContainer = styled.div<
Pick<TextInputV2ComponentProps, 'fullWidth'>
Expand Down Expand Up @@ -185,7 +186,7 @@ const TextInputV2Component = (
onBlur={onBlur}
type={passwordVisible ? 'text' : type}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
onChange?.(event.target.value);
onChange?.(convertToEmptyStringForWhitespaces(event.target.value));
}}
onKeyDown={onKeyDown}
{...{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { Key } from 'ts-key-enum';
import { IconMail, IconSend } from 'twenty-ui';
import { z } from 'zod';
Expand Down Expand Up @@ -71,13 +71,16 @@ export const WorkspaceInviteTeam = () => {
const { enqueueSnackBar } = useSnackBar();
const [sendInviteLink] = useSendInviteLinkMutation();

const { reset, handleSubmit, control, formState } = useForm<FormInput>({
mode: 'onSubmit',
resolver: zodResolver(validationSchema()),
defaultValues: {
emails: '',
const { reset, handleSubmit, control, formState, watch } = useForm<FormInput>(
{
mode: 'onSubmit',
resolver: zodResolver(validationSchema()),
defaultValues: {
emails: '',
},
},
});
);
const isEmailsEmpty = !watch('emails');

const submit = handleSubmit(async (data) => {
const emailsList = sanitizeEmailList(data.emails.split(','));
Expand All @@ -97,7 +100,7 @@ export const WorkspaceInviteTeam = () => {
}
};

const { isSubmitSuccessful } = formState;
const { isSubmitSuccessful, errors } = formState;

useEffect(() => {
if (isSubmitSuccessful) {
Expand Down Expand Up @@ -133,6 +136,7 @@ export const WorkspaceInviteTeam = () => {
accent="blue"
title="Invite"
type="submit"
disabled={isEmailsEmpty || !!errors.emails}
/>
</StyledContainer>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export const SettingsObjects = () => {
{SETTINGS_OBJECT_TABLE_METADATA.fields.map(
(settingsObjectsTableMetadataField) => (
<SortableTableHeader
key={settingsObjectsTableMetadataField.fieldName}
fieldName={settingsObjectsTableMetadataField.fieldName}
label={settingsObjectsTableMetadataField.fieldLabel}
tableId={SETTINGS_OBJECT_TABLE_METADATA.tableId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { SettingsServerlessFunctionSettingsTab } from '@/settings/serverless-fun
import { SettingsServerlessFunctionTestTab } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab';
import { SettingsServerlessFunctionTestTabEffect } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTabEffect';
import { useExecuteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useExecuteOneServerlessFunction';
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
import { usePublishOneServerlessFunction } from '@/settings/serverless-functions/hooks/usePublishOneServerlessFunction';
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
import { usePublishOneServerlessFunction } from '@/settings/serverless-functions/hooks/usePublishOneServerlessFunction';
import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState';
import { settingsServerlessFunctionOutputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionOutputState';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
Expand All @@ -16,14 +17,13 @@ import { Section } from '@/ui/layout/section/components/Section';
import { TabList } from '@/ui/layout/tab/components/TabList';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import isEmpty from 'lodash.isempty';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { IconCode, IconFunction, IconSettings, IconTestPipe } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
import { useDebouncedCallback } from 'use-debounce';
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
import { useState } from 'react';
import isEmpty from 'lodash.isempty';
import { isDefined } from '~/utils/isDefined';

const TAB_LIST_COMPONENT_ID = 'serverless-function-detail';

Expand Down Expand Up @@ -75,7 +75,7 @@ export const SettingsServerlessFunctionDetail = () => {
const handleSave = useDebouncedCallback(save, 500);

const onChange = (key: string) => {
return async (value: string | undefined) => {
return async (value: string) => {
setFormValues((prevState) => ({
...prevState,
[key]: value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const SettingsServerlessFunctionsNew = () => {
};

const onChange = (key: string) => {
return (value: string | undefined) => {
return (value: string) => {
setFormValues((prevState) => ({
...prevState,
[key]: value,
Expand Down
Loading
Loading