feat: gate record creation on isUICreatable only, decoupled from isSystem (#21527)
## Context The generic "create a record" UI affordance previously required `!isSystem`, conflating two distinct concerns: **"hidden from Data Model"** and **"not user-creatable"**. This blocked legitimately creatable system objects (e.g. marketing message lists kept `isSystem: true` only to stay out of the Data Model). This PR makes creatability depend on `isUICreatable` alone, so visibility (`isSystem`) and creatability (`isUICreatable`) become independent. ## Changes - **Front gate** (`canCreateRecordsForObjectMetadataItem.ts`): drop the `!isSystem` clause — creatability is now `isUICreatable && !readOnly`. Updated comment + unit test. - **Command menu** (`standard-command-menu-item.constant.ts`): drop the matching `not objectMetadataItem.isSystem` clause from the `createNewRecord` availability expression so the "Create new X" command mirrors the front gate. Existing workspaces get this via the already-present `SyncCreateRecordCommandAvailabilityExpressionCommand`, which re-syncs from the live definition. - **Standard object audit** (`create-standard-flat-object-metadata.util.ts`): the 15 sync/system-created standard objects that relied on `!isSystem` to stay non-creatable now set `isUICreatable: false` (attachment, blocklist, calendar*/message*/note/task targets, message, messageThread, messageParticipant, timelineActivity, callRecording, workflowAutomatedTrigger, …). `workflowRun`/`workflowVersion`/`workspaceMember` were already `false`. Non-system objects (company, person, note, opportunity, dashboard, task, workflow) are untouched. - **Backfill**: new fast instance command (`2-13-…-1781277480000-backfill-non-ui-creatable-standard-system-objects.ts`) runs `UPDATE core.objectMetadata SET isUICreatable = false` for those standard system objects (symmetric `down`), registered in `instance-commands.constant.ts`. `isSystem` and Data-Model visibility logic are unchanged. ## Verification - Front gate unit test (7 pass), standard-application suite incl. callRecording (10 pass) - `oxlint` clean on all changed files - `twenty-server` and `twenty-front` typecheck green 🤖 https://claude.ai/code/session_01TF4kjD56hHjP31wkHPxPv3 --- _Generated by [Claude Code](https://claude.ai/code/session_01TF4kjD56hHjP31wkHPxPv3)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21527?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -48,7 +48,7 @@ describe('canCreateRecordsForObjectMetadataItem', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when the object is a system object', () => {
|
||||
it('should return true for a UI-creatable system object (isSystem only controls Data-Model visibility)', () => {
|
||||
const result = canCreateRecordsForObjectMetadataItem({
|
||||
objectPermissions: objectPermissionsAllowingUpdate,
|
||||
objectMetadataItem: {
|
||||
@@ -57,7 +57,7 @@ describe('canCreateRecordsForObjectMetadataItem', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when the object is remote', () => {
|
||||
|
||||
+3
-1
@@ -11,6 +11,9 @@ type CanCreateRecordsForObjectMetadataItemParams = {
|
||||
};
|
||||
|
||||
// Single predicate for every generic "create a record" UI affordance.
|
||||
// Creatability is driven solely by isUICreatable: isSystem only controls
|
||||
// Data-Model visibility, so a system object can still be user-creatable
|
||||
// (e.g. marketing message lists kept out of the Data Model).
|
||||
// Creation requires effective editability because today's inline creation UX
|
||||
// creates a blank record that the user must then be able to edit.
|
||||
// There is no CREATE permission yet, so canUpdateObjectRecords (checked
|
||||
@@ -21,7 +24,6 @@ export const canCreateRecordsForObjectMetadataItem = ({
|
||||
}: CanCreateRecordsForObjectMetadataItemParams): boolean => {
|
||||
return (
|
||||
objectMetadataItem.isUICreatable &&
|
||||
!objectMetadataItem.isSystem &&
|
||||
!isObjectMetadataReadOnly({ objectPermissions, objectMetadataItem })
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user