feat: add updatedBy field to track last record modifier (#16807)
<!-- CURSOR_SUMMARY --> > [!NOTE] > Implements last-modifier tracking and unified actor injection. > > - New `ActorFromAuthContextService` replaces createdBy-only logic; pre-query hooks now inject both `createdBy` and `updatedBy` on create and `updatedBy` on update > - Add `updatedBy` standard field to core/custom objects (e.g., `person`, `company`, `task`, `note`, `attachment`, `dashboard`, `workflow`, `workflowRun`) with IDs, metadata builders, and ORM entity fields > - Record CRUD: `create` now sets both `createdBy` and `updatedBy`; `update` sets `updatedBy`; workflow actions use a shared workflow actor builder; REST base handler uses the new actor service > - Seeder data and snapshots updated to include `updatedBy`; GraphQL result formatting adds defaults/handling for empty composite fields (incl. actor) > - Frontend `useUpdateOneRecord` upserts returned record into the local store after mutation > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1f283778e9cb28a35bf84632a1a2997250bb3131. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
+9
@@ -15,6 +15,9 @@ type AttachmentDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
personId: string | null;
|
||||
companyId: string | null;
|
||||
noteId: string | null;
|
||||
@@ -30,6 +33,9 @@ export const ATTACHMENT_DATA_SEED_COLUMNS: (keyof AttachmentDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'personId',
|
||||
'companyId',
|
||||
'noteId',
|
||||
@@ -251,6 +257,9 @@ const GENERATE_ATTACHMENT_SEEDS = (): AttachmentDataSeed[] => {
|
||||
createdBySource: FieldActorSource.MANUAL,
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: FieldActorSource.MANUAL,
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
personId,
|
||||
companyId,
|
||||
noteId,
|
||||
|
||||
+9
@@ -11,6 +11,9 @@ type CompanyDataSeed = {
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
accountOwnerId: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -25,6 +28,9 @@ export const COMPANY_DATA_SEED_COLUMNS: (keyof CompanyDataSeed)[] = [
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'accountOwnerId',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -8524,6 +8530,9 @@ const COMPANY_DATA_SEEDS_RAW = [
|
||||
export const COMPANY_DATA_SEEDS: CompanyDataSeed[] = COMPANY_DATA_SEEDS_RAW.map(
|
||||
(company, index) => ({
|
||||
...company,
|
||||
updatedBySource: company.createdBySource,
|
||||
updatedByWorkspaceMemberId: company.createdByWorkspaceMemberId,
|
||||
updatedByName: company.createdByName,
|
||||
position: index + 1,
|
||||
}),
|
||||
);
|
||||
|
||||
+15
@@ -9,6 +9,9 @@ type DashboardDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -19,6 +22,9 @@ export const DASHBOARD_DATA_SEED_COLUMNS: (keyof DashboardDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -41,6 +47,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim Apple',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim Apple',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
@@ -53,6 +62,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
|
||||
createdByName: 'Jony Ive',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
|
||||
updatedByName: 'Jony Ive',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
@@ -62,6 +74,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
|
||||
createdByName: 'Phil Schiller',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
|
||||
updatedByName: 'Phil Schiller',
|
||||
position: 2,
|
||||
},
|
||||
];
|
||||
|
||||
+12
@@ -10,6 +10,9 @@ type NoteDataSeed = {
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
createdByContext: string | null;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const NOTE_DATA_SEED_COLUMNS: (keyof NoteDataSeed)[] = [
|
||||
@@ -22,6 +25,9 @@ export const NOTE_DATA_SEED_COLUMNS: (keyof NoteDataSeed)[] = [
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'createdByContext',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
const GENERATE_NOTE_IDS = (): Record<string, string> => {
|
||||
@@ -161,6 +167,9 @@ const GENERATE_NOTE_SEEDS = (): NoteDataSeed[] => {
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
createdByContext: null,
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,6 +200,9 @@ const GENERATE_NOTE_SEEDS = (): NoteDataSeed[] => {
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
createdByContext: null,
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -15,6 +15,9 @@ type OpportunityDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const OPPORTUNITY_DATA_SEED_COLUMNS: (keyof OpportunityDataSeed)[] = [
|
||||
@@ -30,6 +33,9 @@ export const OPPORTUNITY_DATA_SEED_COLUMNS: (keyof OpportunityDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
const GENERATE_OPPORTUNITY_IDS = (): Record<string, string> => {
|
||||
@@ -188,6 +194,9 @@ const GENERATE_OPPORTUNITY_SEEDS = (): OpportunityDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim Cook',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim Cook',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -17,6 +17,9 @@ type PersonDataSeed = {
|
||||
phonesPrimaryPhoneNumber: string;
|
||||
phonesPrimaryPhoneCountryCode: string;
|
||||
phonesPrimaryPhoneCallingCode: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -36,6 +39,9 @@ export const PERSON_DATA_SEED_COLUMNS: (keyof PersonDataSeed)[] = [
|
||||
'phonesPrimaryPhoneNumber',
|
||||
'phonesPrimaryPhoneCountryCode',
|
||||
'phonesPrimaryPhoneCallingCode',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -21650,6 +21656,9 @@ const PERSON_DATA_SEEDS_RAW = [
|
||||
export const PERSON_DATA_SEEDS: PersonDataSeed[] = PERSON_DATA_SEEDS_RAW.map(
|
||||
(person, index) => ({
|
||||
...person,
|
||||
updatedBySource: person.createdBySource,
|
||||
updatedByWorkspaceMemberId: person.createdByWorkspaceMemberId,
|
||||
updatedByName: person.createdByName,
|
||||
position: index + 1,
|
||||
}),
|
||||
);
|
||||
|
||||
+12
@@ -12,6 +12,9 @@ type TaskDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const TASK_DATA_SEED_COLUMNS: (keyof TaskDataSeed)[] = [
|
||||
@@ -26,6 +29,9 @@ export const TASK_DATA_SEED_COLUMNS: (keyof TaskDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
// Generate all task IDs
|
||||
@@ -210,6 +216,9 @@ const GENERATE_TASK_SEEDS = (): TaskDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,6 +251,9 @@ const GENERATE_TASK_SEEDS = (): TaskDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user