Surface record selection limit in Workflow Manual Trigger and in Search Node (#15785)
fixes https://github.com/twentyhq/twenty/issues/15704 Take over: https://github.com/twentyhq/twenty/pull/15738 based on [KhademOHAli1](https://github.com/KhademOHAli1) work --------- Co-authored-by: Ali Khadem <ali.kh@pitant.de>
This commit is contained in:
+25
-3
@@ -5,13 +5,16 @@ import { ActionType } from '@/action-menu/actions/types/ActionType';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useActiveWorkflowVersionsWithManualTrigger } from '@/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger';
|
||||
import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion';
|
||||
|
||||
import { type WorkflowVersion } from '@/workflow/types/Workflow';
|
||||
import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
@@ -23,6 +26,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
skip?: boolean;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
const { enqueueWarningSnackBar } = useSnackBar();
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
@@ -49,12 +53,30 @@ export const useRunWorkflowRecordActions = ({
|
||||
'id' | 'workflowId' | 'trigger'
|
||||
>,
|
||||
) => {
|
||||
if (selectedRecordIds.length > QUERY_MAX_RECORDS) {
|
||||
const selectedCountFormatted =
|
||||
selectedRecordIds.length.toLocaleString();
|
||||
const limitFormatted = QUERY_MAX_RECORDS.toLocaleString();
|
||||
|
||||
enqueueWarningSnackBar({
|
||||
message: t`You selected ${selectedCountFormatted} records but manual triggers can run on at most ${limitFormatted} records at once. Only the first ${limitFormatted} records will be processed.`,
|
||||
options: {
|
||||
dedupeKey: 'workflow-manual-trigger-selection-limit',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const limitedSelectedRecordIds = selectedRecordIds.slice(
|
||||
0,
|
||||
QUERY_MAX_RECORDS,
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(activeWorkflowVersion?.trigger) &&
|
||||
isBulkRecordsManualTrigger(activeWorkflowVersion.trigger)
|
||||
) {
|
||||
const objectNamePlural = objectMetadataItem.namePlural;
|
||||
const selectedRecords = selectedRecordIds
|
||||
const selectedRecords = limitedSelectedRecordIds
|
||||
.map((recordId) =>
|
||||
snapshot.getLoadable(recordStoreFamilyState(recordId)).getValue(),
|
||||
)
|
||||
@@ -68,7 +90,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
},
|
||||
});
|
||||
} else {
|
||||
for (const selectedRecordId of selectedRecordIds) {
|
||||
for (const selectedRecordId of limitedSelectedRecordIds) {
|
||||
const selectedRecord = snapshot
|
||||
.getLoadable(recordStoreFamilyState(selectedRecordId))
|
||||
.getValue();
|
||||
@@ -85,7 +107,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
}
|
||||
}
|
||||
},
|
||||
[runWorkflowVersion, objectMetadataItem],
|
||||
[runWorkflowVersion, objectMetadataItem, enqueueWarningSnackBar],
|
||||
);
|
||||
|
||||
return activeWorkflowVersions
|
||||
|
||||
+30
-6
@@ -24,6 +24,7 @@ import { WorkflowFindRecordsSorts } from '@/workflow/workflow-steps/workflow-act
|
||||
import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isNumber } from '@sniptt/guards';
|
||||
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { HorizontalSeparator, useIcons } from 'twenty-ui/display';
|
||||
import { type SelectOption } from 'twenty-ui/input';
|
||||
@@ -66,6 +67,7 @@ export const WorkflowEditActionFindRecords = ({
|
||||
}: WorkflowEditActionFindRecordsProps) => {
|
||||
const { getIcon } = useIcons();
|
||||
const { t } = useLingui();
|
||||
const maxRecordsFormatted = QUERY_MAX_RECORDS.toLocaleString();
|
||||
|
||||
const { activeNonSystemObjectMetadataItems } =
|
||||
useFilteredObjectMetadataItems();
|
||||
@@ -77,12 +79,17 @@ export const WorkflowEditActionFindRecords = ({
|
||||
value: item.nameSingular,
|
||||
}));
|
||||
|
||||
const [formData, setFormData] = useState<FindRecordsFormData>({
|
||||
const [formData, setFormData] = useState<FindRecordsFormData>(() => ({
|
||||
objectNameSingular: action.settings.input.objectName,
|
||||
limit: action.settings.input.limit,
|
||||
limit:
|
||||
isNumber(action.settings.input.limit) &&
|
||||
action.settings.input.limit > QUERY_MAX_RECORDS
|
||||
? QUERY_MAX_RECORDS
|
||||
: (action.settings.input.limit ?? 1),
|
||||
filter: action.settings.input.filter as FindRecordsActionFilter,
|
||||
orderBy: action.settings.input.orderBy as FindRecordsActionOrderBy,
|
||||
});
|
||||
}));
|
||||
const [limitError, setLimitError] = useState<string | undefined>(undefined);
|
||||
const isFormDisabled = actionOptions.readonly ?? false;
|
||||
const instanceId = `workflow-edit-action-record-find-records-${action.id}-${formData.objectNameSingular}`;
|
||||
|
||||
@@ -277,18 +284,35 @@ export const WorkflowEditActionFindRecords = ({
|
||||
)}
|
||||
|
||||
<FormNumberFieldInput
|
||||
label="Limit"
|
||||
label={t`Limit`}
|
||||
defaultValue={formData.limit}
|
||||
placeholder="Enter limit"
|
||||
placeholder={t`Enter limit`}
|
||||
readonly={isFormDisabled}
|
||||
hint={t`This action can return up to ${maxRecordsFormatted} records.`}
|
||||
error={limitError}
|
||||
onChange={(limit) => {
|
||||
if (isFormDisabled === true || !isNumber(limit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalizedLimit = Math.floor(limit);
|
||||
|
||||
if (normalizedLimit <= 0) {
|
||||
setLimitError(t`Limit must be greater than 0.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const cappedLimit = Math.min(normalizedLimit, QUERY_MAX_RECORDS);
|
||||
|
||||
setLimitError(
|
||||
normalizedLimit > QUERY_MAX_RECORDS
|
||||
? t`Limit cannot exceed ${maxRecordsFormatted} records.`
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const newFormData: FindRecordsFormData = {
|
||||
...formData,
|
||||
limit,
|
||||
limit: cappedLimit,
|
||||
};
|
||||
|
||||
setFormData(newFormData);
|
||||
|
||||
+3
-1
@@ -17,6 +17,7 @@ import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTrigge
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
|
||||
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
import { type SelectOption } from 'twenty-ui/input';
|
||||
@@ -61,6 +62,7 @@ export const WorkflowEditTriggerManual = ({
|
||||
const { t } = useLingui();
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
const maxRecordsFormatted = QUERY_MAX_RECORDS.toLocaleString();
|
||||
|
||||
const { activeNonSystemObjectMetadataItems } =
|
||||
useFilteredObjectMetadataItems();
|
||||
@@ -82,7 +84,7 @@ export const WorkflowEditTriggerManual = ({
|
||||
|
||||
const availabilityDescriptions = {
|
||||
SINGLE_RECORD: t`The selected record will be passed to your workflow`,
|
||||
BULK_RECORDS: t`The selected records will be passed to your workflow`,
|
||||
BULK_RECORDS: t`The selected records (up to ${maxRecordsFormatted}) will be passed to your workflow`,
|
||||
GLOBAL: t`No record is required to trigger this workflow`,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user