From c97c71762ea51d9da9e2fe17c5a176425c589505 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras <65061890+Nabhag8848@users.noreply.github.com> Date: Sat, 21 Sep 2024 00:55:50 +0530 Subject: [PATCH] fix: Input fields to have expected behaviour in case of empty / only whitespaces string (#6736) # ISSUE - Closes #6734 - Closes #6633 - Closes #6733 - Closes #6816 # Description - [x] Don't allow Empty (whitespaces) Objects to Create, all the keyboard shortcuts are also handled for this. https://github.com/user-attachments/assets/1c9add4e-f13f-458b-8f76-63bd868413a2 https://github.com/user-attachments/assets/e72b6ee3-74e4-4517-a230-3eb10db80dc7 Note: we do have one other issue with FullName field #6740 Inorder to test use **shift**. - [x] Api Keys Input Name Field -> New and Detail View Name field shouldn't be empty or string with whitespaces, we won't able to have whitespaces in both. **Try Entering just spaces** https://github.com/user-attachments/assets/b521b49f-648c-4585-9d15-8ff4faed3c3a - [x] Similar to above, Empty webhook endpoint url under **/settings/developers/webhooks/new** won't be created. **Try Entering just spaces** - [x] New Functions or Updating Functions will not able to have whitespaces, empty string as Name. **Try Entering just spaces** https://github.com/user-attachments/assets/09fcf394-c6d9-4080-8efd-462b054a22d0 - [x] under **settings/workspace-members** changes will lead and solve that user won't be able to enter Invite by email as just whitespaces + button is now getting disabled when there is no correct email. **Try Entering just spaces** https://github.com/user-attachments/assets/b352edfa-113b-4645-80fd-db6f120ab5db - [x] Text Input Field, will not allow to start entering with whitespaces and won't take just whitespaces as value spaces between words will work. https://github.com/user-attachments/assets/8c1a0812-45be-4ed2-bd3d-bb4f92147976 - [x] Similarly Number works as per above including shortcuts. https://github.com/user-attachments/assets/9f69cc87-5c3c-43ee-93c4-fa887bc0d7ee - [x] Similarly FullName field works as per above including shortcuts https://github.com/user-attachments/assets/7bb006b2-abf7-44cd-a214-7a2fc68df169 - [x] Pasting fullName is been Improved. - Case 1 (Two Words): If there are exactly two words, return them as is. - Case 2 (More than Two Words): If there are more than two words, return the first two words only. - Case 3 (One Word): If there is only one word, return it as the first name, with an empty string as the last name. - WhiteSpaces have been handled. ``` console.log(splitFullName("John Doe")); // ["John", "Doe"] console.log(splitFullName(" ")); // ["", ""] console.log(splitFullName("John")); // ["John", ""] console.log(splitFullName(" John Doe ")); // ["John", "Doe"] console.log(splitFullName("John Michael Andrew Doe")); // ["John", "Michael"] ``` --------- Co-authored-by: Lucas Bordeau --- .../input/components/FullNameFieldInput.tsx | 36 +-- .../components/MultiSelectFieldInput.tsx | 7 +- .../input/components/NumberFieldInput.tsx | 2 +- .../input/components/TextFieldInput.tsx | 14 +- .../input/utils/isDoubleTextFieldEmpty.ts | 9 + .../types/FieldInputDraftValue.ts | 2 +- .../SingleEntitySelectMenuItems.tsx | 7 +- .../workspace/components/NameField.tsx | 4 +- .../input/components/DoubleTextInput.tsx | 19 +- .../field/input/components/TextAreaInput.tsx | 11 +- .../ui/field/input/components/TextInput.tsx | 9 +- .../modules/ui/input/components/TextArea.tsx | 7 +- .../ui/input/components/TextInputV2.tsx | 7 +- .../src/modules/ui/layout/page/PageHeader.tsx | 1 - .../components/WorkspaceInviteTeam.tsx | 18 +- .../SettingsDevelopersWebhookDetail.tsx | 225 +++++++++--------- .../SettingsDevelopersWebhooksNew.tsx | 33 +-- .../SettingsServerlessFunctionDetail.tsx | 2 +- .../SettingsServerlessFunctionsNew.tsx | 2 +- .../src/utils/format/spiltFullName.ts | 13 + .../turnIntoEmptyStringIfWhitespacesOnly.ts | 3 + .../turnIntoUndefinedIfWhitespacesOnly.ts | 5 + 22 files changed, 249 insertions(+), 187 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts create mode 100644 packages/twenty-front/src/utils/format/spiltFullName.ts create mode 100644 packages/twenty-front/src/utils/string/turnIntoEmptyStringIfWhitespacesOnly.ts create mode 100644 packages/twenty-front/src/utils/string/turnIntoUndefinedIfWhitespacesOnly.ts diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx index e7f40c461..c8d7a5f52 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx @@ -3,8 +3,7 @@ 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 { isDoubleTextFieldEmpty } from '@/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty'; import { FieldInputEvent } from './DateTimeFieldInput'; const FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS = @@ -28,46 +27,55 @@ export const FullNameFieldInput = ({ onTab, onShiftTab, }: FullNameFieldInputProps) => { - const { hotkeyScope, draftValue, setDraftValue } = useFullNameField(); - - const persistField = usePersistField(); + const { hotkeyScope, draftValue, setDraftValue, persistFullNameField } = + useFullNameField(); const convertToFullName = (newDoubleText: FieldDoubleText) => { return { - firstName: newDoubleText.firstValue, - lastName: newDoubleText.secondValue, + firstName: newDoubleText.firstValue.trim(), + lastName: newDoubleText.secondValue.trim(), }; }; + const getRequiredDraftValueFromDoubleText = ( + newDoubleText: FieldDoubleText, + ) => { + return isDoubleTextFieldEmpty(newDoubleText) + ? undefined + : convertToFullName(newDoubleText); + }; + 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(getRequiredDraftValueFromDoubleText(newDoubleText)); }; const handlePaste = (newDoubleText: FieldDoubleText) => { - setDraftValue(convertToFullName(newDoubleText)); + setDraftValue(getRequiredDraftValueFromDoubleText(newDoubleText)); }; return ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx index e95eeb5e2..7ebe1951e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx @@ -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 { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; const StyledRelationPickerContainer = styled.div` left: -1px; @@ -109,7 +110,11 @@ export const MultiSelectFieldInput = ({ setSearchFilter(event.currentTarget.value)} + onChange={(event) => + setSearchFilter( + turnIntoEmptyStringIfWhitespacesOnly(event.currentTarget.value), + ) + } autoFocus /> diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx index 336aefc99..d5fead466 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx @@ -60,7 +60,7 @@ export const NumberFieldInput = ({ { - 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(turnIntoUndefinedIfWhitespacesOnly(newText)); }; return ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts new file mode 100644 index 000000000..1ffdc0e78 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts @@ -0,0 +1,9 @@ +import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText'; + +export const isDoubleTextFieldEmpty = (doubleText: FieldDoubleText) => { + const { firstValue, secondValue } = doubleText; + + const totalLength = firstValue.trim().length + secondValue.trim().length; + + return totalLength > 0 ? false : true; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts index 2e50c1b68..9ab99492f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts @@ -25,7 +25,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 FieldPhonesDraftValue = { diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx index 6404d5e11..a7f029e12 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx @@ -1,5 +1,5 @@ import { isNonEmptyString } from '@sniptt/guards'; -import { useRef } from 'react'; +import { Fragment, useRef } from 'react'; import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { IconComponent, IconPlus } from 'twenty-ui'; @@ -158,16 +158,15 @@ export const SingleEntitySelectMenuItems = ({ switch (entity.id) { case 'add-new': { return ( - <> + {entitiesToSelect.length > 0 && } - + ); } case 'select-none': { diff --git a/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx b/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx index 3a921e92f..31b5f31b3 100644 --- a/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx +++ b/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx @@ -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'; @@ -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) { diff --git a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx index 027371815..c003bde59 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx @@ -13,6 +13,8 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { isDefined } from '~/utils/isDefined'; +import { splitFullName } from '~/utils/format/spiltFullName'; +import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; import { StyledTextInput } from './TextInput'; const StyledContainer = styled.div` @@ -167,9 +169,12 @@ export const DoubleTextInput = ({ const name = event.clipboardData.getData('Text'); - const splittedName = name.split(' '); + const splittedName = splitFullName(name); - onPaste?.({ firstValue: splittedName[0], secondValue: splittedName[1] }); + onPaste?.({ + firstValue: splittedName[0], + secondValue: splittedName[1], + }); }; const handleClickToPreventParentClickEvents = ( @@ -189,7 +194,10 @@ export const DoubleTextInput = ({ placeholder={firstValuePlaceholder} value={firstInternalValue} onChange={(event: ChangeEvent) => { - handleChange(event.target.value, secondInternalValue); + handleChange( + turnIntoEmptyStringIfWhitespacesOnly(event.target.value), + secondInternalValue, + ); }} onPaste={(event: ClipboardEvent) => handleOnPaste(event) @@ -203,7 +211,10 @@ export const DoubleTextInput = ({ placeholder={secondValuePlaceholder} value={secondInternalValue} onChange={(event: ChangeEvent) => { - handleChange(firstInternalValue, event.target.value); + handleChange( + firstInternalValue, + turnIntoEmptyStringIfWhitespacesOnly(event.target.value), + ); }} onClick={handleClickToPreventParentClickEvents} /> diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx index b9a08ef1f..c2da43576 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx @@ -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 { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; export type TextAreaInputProps = { disabled?: boolean; @@ -67,10 +68,12 @@ export const TextAreaInput = ({ copyButton = true, }: TextAreaInputProps) => { const [internalText, setInternalText] = useState(value); - const handleChange = (event: ChangeEvent) => { - setInternalText(event.target.value); - onChange?.(event.target.value); + const targetValue = turnIntoEmptyStringIfWhitespacesOnly( + event.target.value, + ); + setInternalText(targetValue); + onChange?.(targetValue); }; const wrapperRef = useRef(null); diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx index 1490e1f7d..b932cbdc5 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx @@ -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'; @@ -44,12 +44,11 @@ export const TextInput = ({ const copyRef = useRef(null); const handleChange = (event: ChangeEvent) => { - setInternalText(event.target.value); - onChange?.(event.target.value); + setInternalText(event.target.value.trim()); + onChange?.(event.target.value.trim()); }; - useEffect(() => { - setInternalText(value); + setInternalText(value.trim()); }, [value]); useRegisterInputEvents({ diff --git a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx index aee5943e6..9b50504c7 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx @@ -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 { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; import { InputHotkeyScope } from '../types/InputHotkeyScope'; const MAX_ROWS = 5; @@ -75,7 +76,9 @@ export const TextArea = ({ maxRows={MAX_ROWS} minRows={computedMinRows} value={value} - onChange={(event) => onChange?.(event.target.value)} + onChange={(event) => + onChange?.(turnIntoEmptyStringIfWhitespacesOnly(event.target.value)) + } onFocus={handleFocus} onBlur={handleBlur} disabled={disabled} diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx index f7a5ddf8b..cf4b06f6a 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx @@ -11,6 +11,7 @@ import { } from 'react'; import { IconComponent, IconEye, IconEyeOff } from 'twenty-ui'; import { useCombinedRefs } from '~/hooks/useCombinedRefs'; +import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; const StyledContainer = styled.div< Pick @@ -180,7 +181,7 @@ const TextInputV2Component = ( )} ) => { - onChange?.(event.target.value); + onChange?.( + turnIntoEmptyStringIfWhitespacesOnly(event.target.value), + ); }} onKeyDown={onKeyDown} {...{ diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx index f352d7343..ed9586bf9 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx @@ -30,7 +30,6 @@ const StyledTopBarContainer = styled.div<{ width?: number }>` padding: ${({ theme }) => theme.spacing(2)}; padding-left: 0; padding-right: ${({ theme }) => theme.spacing(3)}; - z-index: 20; width: ${({ width }) => width + 'px' || '100%'}; @media (max-width: ${MOBILE_VIEWPORT}px) { diff --git a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx index 1f5b277ab..4c007b518 100644 --- a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx +++ b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx @@ -72,13 +72,16 @@ export const WorkspaceInviteTeam = () => { const { enqueueSnackBar } = useSnackBar(); const { sendInvitation } = useCreateWorkspaceInvitation(); - const { reset, handleSubmit, control, formState } = useForm({ - mode: 'onSubmit', - resolver: zodResolver(validationSchema()), - defaultValues: { - emails: '', + const { reset, handleSubmit, control, formState, watch } = useForm( + { + mode: 'onSubmit', + resolver: zodResolver(validationSchema()), + defaultValues: { + emails: '', + }, }, - }); + ); + const isEmailsEmpty = !watch('emails'); const submit = handleSubmit(async ({ emails }) => { const emailsList = sanitizeEmailList(emails.split(',')); @@ -109,7 +112,7 @@ export const WorkspaceInviteTeam = () => { } }; - const { isSubmitSuccessful } = formState; + const { isSubmitSuccessful, errors } = formState; useEffect(() => { if (isSubmitSuccessful) { @@ -144,6 +147,7 @@ export const WorkspaceInviteTeam = () => { accent="blue" title="Invite" type="submit" + disabled={isEmailsEmpty || !!errors.emails} /> diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx index c18292c4c..a45227408 100644 --- a/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx @@ -87,125 +87,116 @@ export const SettingsDevelopersWebhooksDetail = () => { navigate(developerPath); }; + if (!webhookData?.targetUrl) { + return <>; + } + return ( - <> - {webhookData?.targetUrl && ( - { - navigate(developerPath); + { + navigate(developerPath); + }} + onSave={handleSave} + /> + } + > + +
+ + +
+
+ +