Update placeholder on record picker object type update (#11451)

- requires a refacto so several fields can be updated at once
- updating object name on record picker will now update placeholder
- add a min-height to label so fields do not get moved when the label is
deleted
This commit is contained in:
Thomas Trompette
2025-04-08 16:20:15 +02:00
committed by GitHub
parent 6611fbf9ac
commit a049cd4a25
9 changed files with 94 additions and 93 deletions

View File

@ -22,15 +22,15 @@ module.exports = {
parserOptions: { parserOptions: {
project: ['packages/twenty-front/tsconfig.*.json'], project: ['packages/twenty-front/tsconfig.*.json'],
}, },
plugins: ['project-structure'], // plugins: ['project-structure'],
settings: { settings: {
'project-structure/folder-structure-config-path': path.join( // 'project-structure/folder-structure-config-path': path.join(
__dirname, // __dirname,
'folderStructure.json', // 'folderStructure.json',
), // ),
}, },
rules: { rules: {
'project-structure/folder-structure': 'error', // 'project-structure/folder-structure': 'error',
/* /*
Uncomment this rule when we have a way to work on Uncomment this rule when we have a way to work on
'lingui/no-unlocalized-strings': [ 'lingui/no-unlocalized-strings': [

View File

@ -100,6 +100,10 @@ const StyledAddFieldButtonContentContainer = styled.div`
width: 100%; width: 100%;
`; `;
const StyledLabelContainer = styled.div`
min-height: 17px;
`;
export const WorkflowEditActionFormBuilder = ({ export const WorkflowEditActionFormBuilder = ({
action, action,
actionOptions, actionOptions,
@ -187,7 +191,9 @@ export const WorkflowEditActionFormBuilder = ({
<WorkflowStepBody> <WorkflowStepBody>
{formData.map((field) => ( {formData.map((field) => (
<FormFieldInputContainer key={field.id}> <FormFieldInputContainer key={field.id}>
{field.label ? <InputLabel>{field.label}</InputLabel> : null} <StyledLabelContainer>
<InputLabel>{field.label || ''}</InputLabel>
</StyledLabelContainer>
<StyledRowContainer <StyledRowContainer
onMouseEnter={() => setHoveredField(field.id)} onMouseEnter={() => setHoveredField(field.id)}

View File

@ -9,7 +9,6 @@ import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import camelCase from 'lodash.camelcase';
import { IconSettingsAutomation, IconX } from 'twenty-ui/display'; import { IconSettingsAutomation, IconX } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input'; import { LightIconButton } from 'twenty-ui/input';
@ -64,20 +63,6 @@ export const WorkflowEditActionFormFieldSettings = ({
onClose, onClose,
}: WorkflowEditActionFormFieldSettingsProps) => { }: WorkflowEditActionFormFieldSettingsProps) => {
const theme = useTheme(); const theme = useTheme();
const onSubFieldUpdate = (fieldName: string, value: any) => {
if (fieldName === 'label') {
onChange({
...field,
name: camelCase(value),
label: value,
});
} else {
onChange({
...field,
[fieldName]: value,
});
}
};
return ( return (
<StyledFormFieldSettingsContainer> <StyledFormFieldSettingsContainer>
@ -119,15 +104,13 @@ export const WorkflowEditActionFormFieldSettings = ({
name, name,
label, label,
settings, settings,
placeholder: '',
}); });
}} }}
defaultValue={field.type} defaultValue={field.type}
/> />
</FormFieldInputContainer> </FormFieldInputContainer>
<WorkflowFormFieldSettingsByType <WorkflowFormFieldSettingsByType field={field} onChange={onChange} />
field={field}
onChange={onSubFieldUpdate}
/>
</StyledSettingsContent> </StyledSettingsContent>
</StyledFormFieldSettingsContainer> </StyledFormFieldSettingsContainer>
); );

View File

@ -11,46 +11,26 @@ export const WorkflowFormFieldSettingsByType = ({
onChange, onChange,
}: { }: {
field: WorkflowFormActionField; field: WorkflowFormActionField;
onChange: (fieldName: string, value: unknown) => void; onChange: (updatedField: WorkflowFormActionField) => void;
}) => { }) => {
switch (field.type) { switch (field.type) {
case FieldMetadataType.TEXT: case FieldMetadataType.TEXT:
return ( return (
<WorkflowFormFieldSettingsText <WorkflowFormFieldSettingsText field={field} onChange={onChange} />
label={field.label}
placeholder={field.placeholder}
onChange={(fieldName, value) => {
onChange(fieldName, value);
}}
/>
); );
case FieldMetadataType.NUMBER: case FieldMetadataType.NUMBER:
return ( return (
<WorkflowFormFieldSettingsNumber <WorkflowFormFieldSettingsNumber field={field} onChange={onChange} />
label={field.label}
placeholder={field.placeholder}
onChange={(fieldName, value) => {
onChange(fieldName, value);
}}
/>
); );
case FieldMetadataType.DATE: case FieldMetadataType.DATE:
return ( return (
<WorkflowFormFieldSettingsDate <WorkflowFormFieldSettingsDate field={field} onChange={onChange} />
label={field.label}
onChange={(fieldName, value) => {
onChange(fieldName, value);
}}
/>
); );
case 'RECORD': case 'RECORD':
return ( return (
<WorkflowFormFieldSettingsRecordPicker <WorkflowFormFieldSettingsRecordPicker
label={field.label} field={field}
settings={field.settings} onChange={onChange}
onChange={(fieldName, value) => {
onChange(fieldName, value);
}}
/> />
); );
default: default:

View File

@ -1,26 +1,32 @@
import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer'; import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer';
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
import { InputLabel } from '@/ui/input/components/InputLabel'; import { InputLabel } from '@/ui/input/components/InputLabel';
import { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
import camelCase from 'lodash.camelcase';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
type WorkflowFormFieldSettingsDateProps = { type WorkflowFormFieldSettingsDateProps = {
label?: string; field: WorkflowFormActionField;
onChange: (fieldName: string, value: string | null) => void; onChange: (updatedField: WorkflowFormActionField) => void;
}; };
export const WorkflowFormFieldSettingsDate = ({ export const WorkflowFormFieldSettingsDate = ({
label, field,
onChange, onChange,
}: WorkflowFormFieldSettingsDateProps) => { }: WorkflowFormFieldSettingsDateProps) => {
return ( return (
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Label</InputLabel> <InputLabel>Label</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newLabel: string | null) => { onChange={(newLabel: string) => {
onChange('label', newLabel); onChange({
...field,
label: newLabel,
name: camelCase(newLabel),
});
}} }}
defaultValue={label} defaultValue={field.label}
placeholder={getDefaultFormFieldSettings(FieldMetadataType.DATE).label} placeholder={getDefaultFormFieldSettings(FieldMetadataType.DATE).label}
/> />
</FormFieldInputContainer> </FormFieldInputContainer>

View File

@ -1,14 +1,15 @@
import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer'; import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer';
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
import { InputLabel } from '@/ui/input/components/InputLabel'; import { InputLabel } from '@/ui/input/components/InputLabel';
import { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import camelCase from 'lodash.camelcase';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
type WorkflowFormFieldSettingsNumberProps = { type WorkflowFormFieldSettingsNumberProps = {
label?: string; field: WorkflowFormActionField;
placeholder?: string; onChange: (updatedField: WorkflowFormActionField) => void;
onChange: (fieldName: string, value: string | null) => void;
}; };
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -18,8 +19,7 @@ const StyledContainer = styled.div`
`; `;
export const WorkflowFormFieldSettingsNumber = ({ export const WorkflowFormFieldSettingsNumber = ({
label, field,
placeholder,
onChange, onChange,
}: WorkflowFormFieldSettingsNumberProps) => { }: WorkflowFormFieldSettingsNumberProps) => {
return ( return (
@ -27,10 +27,14 @@ export const WorkflowFormFieldSettingsNumber = ({
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Label</InputLabel> <InputLabel>Label</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newLabel: string | null) => { onChange={(newLabel: string) => {
onChange('label', newLabel); onChange({
...field,
label: newLabel,
name: camelCase(newLabel),
});
}} }}
defaultValue={label} defaultValue={field.label}
placeholder={ placeholder={
getDefaultFormFieldSettings(FieldMetadataType.NUMBER).label getDefaultFormFieldSettings(FieldMetadataType.NUMBER).label
} }
@ -39,10 +43,13 @@ export const WorkflowFormFieldSettingsNumber = ({
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Placeholder</InputLabel> <InputLabel>Placeholder</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newPlaceholder: string | null) => { onChange={(newPlaceholder: string) => {
onChange('placeholder', newPlaceholder); onChange({
...field,
placeholder: newPlaceholder,
});
}} }}
defaultValue={placeholder} defaultValue={field.placeholder}
placeholder={ placeholder={
getDefaultFormFieldSettings(FieldMetadataType.NUMBER).placeholder getDefaultFormFieldSettings(FieldMetadataType.NUMBER).placeholder
} }

View File

@ -3,15 +3,16 @@ import { FormFieldInputContainer } from '@/object-record/record-field/form-types
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
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 { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import camelCase from 'lodash.camelcase';
import { useIcons } from 'twenty-ui/display'; import { useIcons } from 'twenty-ui/display';
import { SelectOption } from 'twenty-ui/input'; import { SelectOption } from 'twenty-ui/input';
type WorkflowFormFieldSettingsRecordPickerProps = { type WorkflowFormFieldSettingsRecordPickerProps = {
label?: string; field: WorkflowFormActionField;
settings?: Record<string, any>; onChange: (updatedField: WorkflowFormActionField) => void;
onChange: (fieldName: string, value: unknown) => void;
}; };
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -21,8 +22,7 @@ const StyledContainer = styled.div`
`; `;
export const WorkflowFormFieldSettingsRecordPicker = ({ export const WorkflowFormFieldSettingsRecordPicker = ({
label, field,
settings,
onChange, onChange,
}: WorkflowFormFieldSettingsRecordPickerProps) => { }: WorkflowFormFieldSettingsRecordPickerProps) => {
const { getIcon } = useIcons(); const { getIcon } = useIcons();
@ -43,13 +43,21 @@ export const WorkflowFormFieldSettingsRecordPicker = ({
dropdownId="workflow-form-field-settings-record-picker-object-name" dropdownId="workflow-form-field-settings-record-picker-object-name"
label="Object" label="Object"
fullWidth fullWidth
value={settings?.objectName} value={field.settings?.objectName}
emptyOption={{ label: 'Select an option', value: '' }} emptyOption={{ label: 'Select an option', value: '' }}
options={availableMetadata} options={availableMetadata}
onChange={(updatedObjectName) => { onChange={(updatedObjectName) => {
onChange('settings', { onChange({
...settings, ...field,
objectName: updatedObjectName, placeholder: `Select a ${
activeObjectMetadataItems.find(
(item) => item.nameSingular === updatedObjectName,
)?.labelSingular || 'record'
}`,
settings: {
...field.settings,
objectName: updatedObjectName,
},
}); });
}} }}
withSearchInput withSearchInput
@ -58,10 +66,14 @@ export const WorkflowFormFieldSettingsRecordPicker = ({
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Label</InputLabel> <InputLabel>Label</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newLabel: string | null) => { onChange={(newLabel: string) => {
onChange('label', newLabel); onChange({
...field,
label: newLabel,
name: camelCase(newLabel),
});
}} }}
defaultValue={label} defaultValue={field.label}
placeholder={getDefaultFormFieldSettings('RECORD').label} placeholder={getDefaultFormFieldSettings('RECORD').label}
/> />
</FormFieldInputContainer> </FormFieldInputContainer>

View File

@ -1,14 +1,15 @@
import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer'; import { FormFieldInputContainer } from '@/object-record/record-field/form-types/components/FormFieldInputContainer';
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
import { InputLabel } from '@/ui/input/components/InputLabel'; import { InputLabel } from '@/ui/input/components/InputLabel';
import { WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField';
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import camelCase from 'lodash.camelcase';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
type WorkflowFormFieldSettingsTextProps = { type WorkflowFormFieldSettingsTextProps = {
label?: string; field: WorkflowFormActionField;
placeholder?: string; onChange: (updatedField: WorkflowFormActionField) => void;
onChange: (fieldName: string, value: string | null) => void;
}; };
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -18,8 +19,7 @@ const StyledContainer = styled.div`
`; `;
export const WorkflowFormFieldSettingsText = ({ export const WorkflowFormFieldSettingsText = ({
label, field,
placeholder,
onChange, onChange,
}: WorkflowFormFieldSettingsTextProps) => { }: WorkflowFormFieldSettingsTextProps) => {
return ( return (
@ -27,10 +27,14 @@ export const WorkflowFormFieldSettingsText = ({
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Label</InputLabel> <InputLabel>Label</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newLabel: string | null) => { onChange={(newLabel: string) => {
onChange('label', newLabel); onChange({
...field,
label: newLabel,
name: camelCase(newLabel),
});
}} }}
defaultValue={label} defaultValue={field.label}
placeholder={ placeholder={
getDefaultFormFieldSettings(FieldMetadataType.TEXT).label getDefaultFormFieldSettings(FieldMetadataType.TEXT).label
} }
@ -39,10 +43,13 @@ export const WorkflowFormFieldSettingsText = ({
<FormFieldInputContainer> <FormFieldInputContainer>
<InputLabel>Placeholder</InputLabel> <InputLabel>Placeholder</InputLabel>
<FormTextFieldInput <FormTextFieldInput
onChange={(newPlaceholder: string | null) => { onChange={(newPlaceholder: string) => {
onChange('placeholder', newPlaceholder); onChange({
...field,
placeholder: newPlaceholder,
});
}} }}
defaultValue={placeholder} defaultValue={field.placeholder}
placeholder={ placeholder={
getDefaultFormFieldSettings(FieldMetadataType.TEXT).placeholder getDefaultFormFieldSettings(FieldMetadataType.TEXT).placeholder
} }

View File

@ -31,7 +31,7 @@ export const getDefaultFormFieldSettings = (type: WorkflowFormFieldType) => {
id: v4(), id: v4(),
name: 'record', name: 'record',
label: 'Record', label: 'Record',
placeholder: `Select a record`, placeholder: `Select a Company`,
settings: { settings: {
objectName: 'company', objectName: 'company',
}, },