Form action fast follows (#11242)
- on form action, add trash on hover and fix spacing - fix dark mode - second batch of icon fixes <img width="692" alt="Capture d’écran 2025-03-27 à 18 25 48" src="https://github.com/user-attachments/assets/963f50d2-12ee-425c-97a3-2ad0c6bb5c57" />
This commit is contained in:
@ -39,7 +39,6 @@ import {
|
|||||||
IconFileImport,
|
IconFileImport,
|
||||||
IconHeart,
|
IconHeart,
|
||||||
IconHeartOff,
|
IconHeartOff,
|
||||||
IconHistory,
|
|
||||||
IconHistoryToggle,
|
IconHistoryToggle,
|
||||||
IconNoteOff,
|
IconNoteOff,
|
||||||
IconPlayerPause,
|
IconPlayerPause,
|
||||||
@ -49,6 +48,7 @@ import {
|
|||||||
IconRotate2,
|
IconRotate2,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
IconTrashX,
|
IconTrashX,
|
||||||
|
IconVersions,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const WORKFLOW_ACTIONS_CONFIG: Record<
|
export const WORKFLOW_ACTIONS_CONFIG: Record<
|
||||||
@ -120,7 +120,7 @@ export const WORKFLOW_ACTIONS_CONFIG: Record<
|
|||||||
shortLabel: msg`See active version`,
|
shortLabel: msg`See active version`,
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
position: 4,
|
position: 4,
|
||||||
Icon: IconHistory,
|
Icon: IconVersions,
|
||||||
type: ActionMenuEntryType.Standard,
|
type: ActionMenuEntryType.Standard,
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
availableOn: [
|
availableOn: [
|
||||||
@ -150,7 +150,7 @@ export const WORKFLOW_ACTIONS_CONFIG: Record<
|
|||||||
shortLabel: msg`See versions`,
|
shortLabel: msg`See versions`,
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
position: 6,
|
position: 6,
|
||||||
Icon: IconHistory,
|
Icon: IconVersions,
|
||||||
type: ActionMenuEntryType.Standard,
|
type: ActionMenuEntryType.Standard,
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
availableOn: [
|
availableOn: [
|
||||||
|
|||||||
@ -27,9 +27,9 @@ import {
|
|||||||
IconEyeOff,
|
IconEyeOff,
|
||||||
IconHeart,
|
IconHeart,
|
||||||
IconHeartOff,
|
IconHeartOff,
|
||||||
IconHistory,
|
|
||||||
IconRotate2,
|
IconRotate2,
|
||||||
IconSettingsAutomation,
|
IconSettingsAutomation,
|
||||||
|
IconVersions,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const WORKFLOW_RUNS_ACTIONS_CONFIG: Record<
|
export const WORKFLOW_RUNS_ACTIONS_CONFIG: Record<
|
||||||
@ -61,7 +61,7 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG: Record<
|
|||||||
isPinned: true,
|
isPinned: true,
|
||||||
type: ActionMenuEntryType.Standard,
|
type: ActionMenuEntryType.Standard,
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
Icon: IconHistory,
|
Icon: IconVersions,
|
||||||
availableOn: [
|
availableOn: [
|
||||||
ActionViewType.SHOW_PAGE,
|
ActionViewType.SHOW_PAGE,
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||||
|
|||||||
@ -30,11 +30,11 @@ import {
|
|||||||
IconEyeOff,
|
IconEyeOff,
|
||||||
IconHeart,
|
IconHeart,
|
||||||
IconHeartOff,
|
IconHeartOff,
|
||||||
IconHistory,
|
|
||||||
IconHistoryToggle,
|
IconHistoryToggle,
|
||||||
IconPencil,
|
IconPencil,
|
||||||
IconRotate2,
|
IconRotate2,
|
||||||
IconSettingsAutomation,
|
IconSettingsAutomation,
|
||||||
|
IconVersions,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record<
|
export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record<
|
||||||
@ -95,7 +95,7 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record<
|
|||||||
position: 4,
|
position: 4,
|
||||||
type: ActionMenuEntryType.Standard,
|
type: ActionMenuEntryType.Standard,
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
Icon: IconHistory,
|
Icon: IconVersions,
|
||||||
availableOn: [
|
availableOn: [
|
||||||
ActionViewType.SHOW_PAGE,
|
ActionViewType.SHOW_PAGE,
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||||
|
|||||||
@ -81,13 +81,18 @@ const StyledIconButtonContainer = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledAddFieldContainer = styled.div`
|
const StyledAddFieldButtonContainer = styled.div`
|
||||||
display: flex;
|
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledAddFieldButtonContentContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
display: flex;
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
gap: ${({ theme }) => theme.spacing(0.5)};
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: ${({ theme }) => theme.spacing(0.5)};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const WorkflowEditActionFormBuilder = ({
|
export const WorkflowEditActionFormBuilder = ({
|
||||||
@ -106,7 +111,9 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
const headerType = useActionHeaderTypeOrThrow(action.type);
|
const headerType = useActionHeaderTypeOrThrow(action.type);
|
||||||
|
|
||||||
const [selectedField, setSelectedField] = useState<string | null>(null);
|
const [selectedField, setSelectedField] = useState<string | null>(null);
|
||||||
|
const [hoveredField, setHoveredField] = useState<string | null>(null);
|
||||||
const isFieldSelected = (fieldName: string) => selectedField === fieldName;
|
const isFieldSelected = (fieldName: string) => selectedField === fieldName;
|
||||||
|
const isFieldHovered = (fieldName: string) => hoveredField === fieldName;
|
||||||
const handleFieldClick = (fieldName: string) => {
|
const handleFieldClick = (fieldName: string) => {
|
||||||
if (actionOptions.readonly === true) {
|
if (actionOptions.readonly === true) {
|
||||||
return;
|
return;
|
||||||
@ -177,7 +184,10 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
<FormFieldInputContainer key={field.id}>
|
<FormFieldInputContainer key={field.id}>
|
||||||
{field.label ? <InputLabel>{field.label}</InputLabel> : null}
|
{field.label ? <InputLabel>{field.label}</InputLabel> : null}
|
||||||
|
|
||||||
<StyledRowContainer>
|
<StyledRowContainer
|
||||||
|
onMouseEnter={() => setHoveredField(field.id)}
|
||||||
|
onMouseLeave={() => setHoveredField(null)}
|
||||||
|
>
|
||||||
<FormFieldInputRowContainer>
|
<FormFieldInputRowContainer>
|
||||||
<FormFieldInputInputContainer
|
<FormFieldInputInputContainer
|
||||||
hasRightElement={false}
|
hasRightElement={false}
|
||||||
@ -201,29 +211,30 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
</StyledFieldContainer>
|
</StyledFieldContainer>
|
||||||
</FormFieldInputInputContainer>
|
</FormFieldInputInputContainer>
|
||||||
</FormFieldInputRowContainer>
|
</FormFieldInputRowContainer>
|
||||||
{!actionOptions.readonly && isFieldSelected(field.id) && (
|
{!actionOptions.readonly &&
|
||||||
<StyledIconButtonContainer>
|
(isFieldSelected(field.id) || isFieldHovered(field.id)) && (
|
||||||
<IconTrash
|
<StyledIconButtonContainer>
|
||||||
size={theme.icon.size.md}
|
<IconTrash
|
||||||
color={theme.font.color.secondary}
|
size={theme.icon.size.md}
|
||||||
onClick={() => {
|
color={theme.font.color.secondary}
|
||||||
const updatedFormData = formData.filter(
|
onClick={() => {
|
||||||
(currentField) => currentField.id !== field.id,
|
const updatedFormData = formData.filter(
|
||||||
);
|
(currentField) => currentField.id !== field.id,
|
||||||
|
);
|
||||||
|
|
||||||
setFormData(updatedFormData);
|
setFormData(updatedFormData);
|
||||||
|
|
||||||
actionOptions.onActionUpdate({
|
actionOptions.onActionUpdate({
|
||||||
...action,
|
...action,
|
||||||
settings: {
|
settings: {
|
||||||
...action.settings,
|
...action.settings,
|
||||||
input: updatedFormData,
|
input: updatedFormData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledIconButtonContainer>
|
</StyledIconButtonContainer>
|
||||||
)}
|
)}
|
||||||
{isFieldSelected(field.id) && (
|
{isFieldSelected(field.id) && (
|
||||||
<WorkflowEditActionFormFieldSettings
|
<WorkflowEditActionFormFieldSettings
|
||||||
field={field}
|
field={field}
|
||||||
@ -237,44 +248,46 @@ export const WorkflowEditActionFormBuilder = ({
|
|||||||
</FormFieldInputContainer>
|
</FormFieldInputContainer>
|
||||||
))}
|
))}
|
||||||
{!actionOptions.readonly && (
|
{!actionOptions.readonly && (
|
||||||
<StyledRowContainer>
|
<StyledAddFieldButtonContainer>
|
||||||
<FormFieldInputContainer>
|
<StyledRowContainer>
|
||||||
<FormFieldInputRowContainer>
|
<FormFieldInputContainer>
|
||||||
<FormFieldInputInputContainer
|
<FormFieldInputRowContainer>
|
||||||
hasRightElement={false}
|
<FormFieldInputInputContainer
|
||||||
onClick={() => {
|
hasRightElement={false}
|
||||||
const { label, placeholder, name } =
|
onClick={() => {
|
||||||
getDefaultFormFieldSettings(FieldMetadataType.TEXT);
|
const { label, placeholder, name } =
|
||||||
|
getDefaultFormFieldSettings(FieldMetadataType.TEXT);
|
||||||
|
|
||||||
const newField: WorkflowFormActionField = {
|
const newField: WorkflowFormActionField = {
|
||||||
id: v4(),
|
id: v4(),
|
||||||
name,
|
name,
|
||||||
type: FieldMetadataType.TEXT,
|
type: FieldMetadataType.TEXT,
|
||||||
label,
|
label,
|
||||||
placeholder,
|
placeholder,
|
||||||
};
|
};
|
||||||
|
|
||||||
setFormData([...formData, newField]);
|
setFormData([...formData, newField]);
|
||||||
|
|
||||||
actionOptions.onActionUpdate({
|
actionOptions.onActionUpdate({
|
||||||
...action,
|
...action,
|
||||||
settings: {
|
settings: {
|
||||||
...action.settings,
|
...action.settings,
|
||||||
input: [...action.settings.input, newField],
|
input: [...action.settings.input, newField],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledFieldContainer>
|
<StyledFieldContainer>
|
||||||
<StyledAddFieldContainer>
|
<StyledAddFieldButtonContentContainer>
|
||||||
<IconPlus size={theme.icon.size.sm} />
|
<IconPlus size={theme.icon.size.sm} />
|
||||||
{t`Add Field`}
|
{t`Add Field`}
|
||||||
</StyledAddFieldContainer>
|
</StyledAddFieldButtonContentContainer>
|
||||||
</StyledFieldContainer>
|
</StyledFieldContainer>
|
||||||
</FormFieldInputInputContainer>
|
</FormFieldInputInputContainer>
|
||||||
</FormFieldInputRowContainer>
|
</FormFieldInputRowContainer>
|
||||||
</FormFieldInputContainer>
|
</FormFieldInputContainer>
|
||||||
</StyledRowContainer>
|
</StyledRowContainer>
|
||||||
|
</StyledAddFieldButtonContainer>
|
||||||
)}
|
)}
|
||||||
</WorkflowStepBody>
|
</WorkflowStepBody>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -44,12 +44,14 @@ const StyledSettingsHeader = styled.div`
|
|||||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
padding-inline: ${({ theme }) => theme.spacing(3)};
|
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(3)};
|
||||||
grid-template-columns: 1fr 24px;
|
grid-template-columns: 1fr 24px;
|
||||||
padding-bottom: ${({ theme }) => theme.spacing(3)};
|
padding-bottom: ${({ theme }) => theme.spacing(3)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledTitleContainer = styled.div`
|
const StyledTitleContainer = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export const workflowRunsAllView = (
|
|||||||
type: 'table',
|
type: 'table',
|
||||||
key: 'INDEX',
|
key: 'INDEX',
|
||||||
position: 0,
|
position: 0,
|
||||||
icon: 'IconHistory',
|
icon: 'IconHistoryToggle',
|
||||||
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
|
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
|
||||||
kanbanFieldMetadataId: '',
|
kanbanFieldMetadataId: '',
|
||||||
filters: [],
|
filters: [],
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
WorkflowRunStatus,
|
WorkflowRunStatus,
|
||||||
WorkflowRunWorkspaceEntity,
|
WorkflowRunWorkspaceEntity,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||||
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||||
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
import {
|
import {
|
||||||
@ -39,12 +40,36 @@ export class WorkflowRunWorkspaceService {
|
|||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const workflowRepository =
|
||||||
|
await this.twentyORMManager.getRepository<WorkflowWorkspaceEntity>(
|
||||||
|
'workflow',
|
||||||
|
);
|
||||||
|
|
||||||
|
const workflow = await workflowRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: workflowVersion.workflowId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!workflow) {
|
||||||
|
throw new WorkflowRunException(
|
||||||
|
'Workflow id is invalid',
|
||||||
|
WorkflowRunExceptionCode.WORKFLOW_RUN_INVALID,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflowRunCount = await workflowRunRepository.count({
|
||||||
|
where: {
|
||||||
|
workflowId: workflow.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
await workflowRunRepository.save({
|
await workflowRunRepository.save({
|
||||||
name: `Execution of ${workflowVersion.name}`,
|
name: `#${workflowRunCount + 1} - ${workflow.name}`,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
createdBy,
|
createdBy,
|
||||||
workflowId: workflowVersion.workflowId,
|
workflowId: workflow.id,
|
||||||
status: WorkflowRunStatus.NOT_STARTED,
|
status: WorkflowRunStatus.NOT_STARTED,
|
||||||
})
|
})
|
||||||
).id;
|
).id;
|
||||||
|
|||||||
@ -203,6 +203,7 @@ export {
|
|||||||
IconMinus,
|
IconMinus,
|
||||||
IconMoneybag,
|
IconMoneybag,
|
||||||
IconMoodSmile,
|
IconMoodSmile,
|
||||||
|
IconMoon,
|
||||||
IconMouse2,
|
IconMouse2,
|
||||||
IconNorthStar,
|
IconNorthStar,
|
||||||
IconNoteOff,
|
IconNoteOff,
|
||||||
@ -262,6 +263,9 @@ export {
|
|||||||
IconSquareRoundedX,
|
IconSquareRoundedX,
|
||||||
IconStatusChange,
|
IconStatusChange,
|
||||||
IconStepInto,
|
IconStepInto,
|
||||||
|
IconSun,
|
||||||
|
IconSunMoon,
|
||||||
|
IconSwitchHorizontal,
|
||||||
IconTable,
|
IconTable,
|
||||||
IconTag,
|
IconTag,
|
||||||
IconTags,
|
IconTags,
|
||||||
@ -281,16 +285,13 @@ export {
|
|||||||
IconUpload,
|
IconUpload,
|
||||||
IconUser,
|
IconUser,
|
||||||
IconUserCircle,
|
IconUserCircle,
|
||||||
IconSwitchHorizontal,
|
|
||||||
IconUserCog,
|
IconUserCog,
|
||||||
IconUserPin,
|
IconUserPin,
|
||||||
IconUserPlus,
|
IconUserPlus,
|
||||||
IconSunMoon,
|
|
||||||
IconMoon,
|
|
||||||
IconSun,
|
|
||||||
IconUsers,
|
IconUsers,
|
||||||
IconVariable,
|
IconVariable,
|
||||||
IconVariablePlus,
|
IconVariablePlus,
|
||||||
|
IconVersions,
|
||||||
IconVideo,
|
IconVideo,
|
||||||
IconWand,
|
IconWand,
|
||||||
IconWebhook,
|
IconWebhook,
|
||||||
|
|||||||
Reference in New Issue
Block a user