System view tooling explicit params key naming (#23506)

# Introduction
View field system always result from a field existence, the application
universal identifier should be the related field one
Same but for views and object

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23506?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. -->
This commit is contained in:
Paul Rastoin
2026-07-29 16:33:40 +02:00
committed by GitHub
parent 33970dd45d
commit 4ec65ed08d
22 changed files with 192 additions and 67 deletions
@@ -2,8 +2,8 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Command } from 'nest-commander';
import {
getSystemViewFieldUniversalIdentifier,
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { ViewKey } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -34,7 +34,7 @@ type ReownUpdate = {
@Command({
name: 'upgrade:2-26:reconcile-index-view-universal-identifier',
description:
'Re-own the INDEX table views ("All {objectLabelPlural}", keyed on ViewKey.INDEX) of the twenty-standard and workspace-custom applications, and all their view fields, onto the engine convention: the view gets the name-free deterministic universal identifier (getSystemViewUniversalIdentifier, object identifier + INDEX key), each view field gets the derived getViewFieldUniversalIdentifier keyed on the application of the field it DISPLAYS — not the row attribution, which diverges when a user shows a hidden standard column and mints a workspace-custom view field on a standard field — so an app or user column on a standard INDEX view converges too, and both get isSystemSideEffect: true, as if provisioned by the metadata side-effect engine. INDEX views of other applications are handled by the demote-and-backfill command. Children reference the view by primary key, so the re-own is a lossless update.',
'Re-own the INDEX table views ("All {objectLabelPlural}", keyed on ViewKey.INDEX) of the twenty-standard and workspace-custom applications, and all their view fields, onto the engine convention: the view gets the name-free deterministic universal identifier (getSystemViewUniversalIdentifier, object identifier + INDEX key), each view field gets the derived getSystemViewFieldUniversalIdentifier keyed on the application of the field it DISPLAYS — not the row attribution, which diverges when a user shows a hidden standard column and mints a workspace-custom view field on a standard field — so an app or user column on a standard INDEX view converges too, and both get isSystemSideEffect: true, as if provisioned by the metadata side-effect engine. INDEX views of other applications are handled by the demote-and-backfill command. Children reference the view by primary key, so the re-own is a lossless update.',
})
export class ReconcileIndexViewUniversalIdentifierCommand extends ProvisionedWorkspaceCommandRunner {
constructor(
@@ -171,7 +171,7 @@ export class ReconcileIndexViewUniversalIdentifierCommand extends ProvisionedWor
}
const derivedViewUniversalIdentifier = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier:
objectMetadataApplicationUniversalIdentifier:
flatObjectMetadata.applicationUniversalIdentifier,
objectUniversalIdentifier: flatObjectMetadata.universalIdentifier,
viewKey: ViewKey.INDEX,
@@ -261,15 +261,14 @@ export class ReconcileIndexViewUniversalIdentifierCommand extends ProvisionedWor
return undefined;
}
const derivedViewFieldUniversalIdentifier = getViewFieldUniversalIdentifier(
{
applicationUniversalIdentifier:
const derivedViewFieldUniversalIdentifier =
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
flatFieldMetadata.applicationUniversalIdentifier,
viewUniversalIdentifier: derivedViewUniversalIdentifier,
fieldMetadataUniversalIdentifier:
flatViewField.fieldMetadataUniversalIdentifier,
},
);
});
const update: ReownUpdate['update'] = {};
@@ -2,8 +2,8 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Command } from 'nest-commander';
import {
getSystemViewFieldUniversalIdentifier,
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { ViewKey } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -220,7 +220,7 @@ export class DemoteAndBackfillApplicationIndexViewCommand extends ProvisionedWor
}
const indexViewUniversalIdentifier = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier:
objectMetadataApplicationUniversalIdentifier:
flatObjectMetadata.applicationUniversalIdentifier,
objectUniversalIdentifier: flatObjectMetadata.universalIdentifier,
viewKey: ViewKey.INDEX,
@@ -276,12 +276,14 @@ export class DemoteAndBackfillApplicationIndexViewCommand extends ProvisionedWor
const fieldApplicationUniversalIdentifier =
flatFieldMetadata.applicationUniversalIdentifier;
const viewFieldUniversalIdentifier = getViewFieldUniversalIdentifier({
applicationUniversalIdentifier: fieldApplicationUniversalIdentifier,
viewUniversalIdentifier: indexViewUniversalIdentifier,
fieldMetadataUniversalIdentifier:
flatFieldMetadata.universalIdentifier,
});
const viewFieldUniversalIdentifier =
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
fieldApplicationUniversalIdentifier,
viewUniversalIdentifier: indexViewUniversalIdentifier,
fieldMetadataUniversalIdentifier:
flatFieldMetadata.universalIdentifier,
});
// Already backfilled by a previous (partially failed) run.
if (
@@ -1,6 +1,6 @@
import {
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
getSystemViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { ViewKey } from 'twenty-shared/types';
@@ -27,13 +27,13 @@ const FIELD_UNIVERSAL_IDENTIFIER = '20202020-0000-4000-8000-0000000000cc';
const DERIVED_STANDARD_VIEW_UNIVERSAL_IDENTIFIER =
getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier: STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
const DERIVED_STANDARD_VIEW_FIELD_UNIVERSAL_IDENTIFIER =
getViewFieldUniversalIdentifier({
applicationUniversalIdentifier: STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier: STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_STANDARD_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: FIELD_UNIVERSAL_IDENTIFIER,
});
@@ -248,7 +248,7 @@ describe('ReconcileIndexViewUniversalIdentifierCommand', () => {
it('re-owns a custom object INDEX view onto the workspace-custom derivation', async () => {
const derivedCustomViewUniversalIdentifier =
getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: CUSTOM_APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier: CUSTOM_APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: CUSTOM_OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
@@ -367,8 +367,8 @@ describe('ReconcileIndexViewUniversalIdentifierCommand', () => {
// those must converge on the derived scheme so manifest deletion inference
// never drops them once the app stops declaring them.
const derivedExternalViewFieldUniversalIdentifier =
getViewFieldUniversalIdentifier({
applicationUniversalIdentifier:
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_STANDARD_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: FIELD_UNIVERSAL_IDENTIFIER,
@@ -1,6 +1,6 @@
import {
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
getSystemViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { FieldMetadataType, ViewKey } from 'twenty-shared/types';
import { In } from 'typeorm';
@@ -23,7 +23,7 @@ const OBJECT_UNIVERSAL_IDENTIFIER = '20202020-0000-4000-8000-0000000000bb';
const FIELD_UNIVERSAL_IDENTIFIER = '20202020-0000-4000-8000-0000000000cc';
const DERIVED_VIEW_UNIVERSAL_IDENTIFIER = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier: EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
@@ -205,8 +205,8 @@ describe('DemoteAndBackfillApplicationIndexViewCommand', () => {
.flatEntityToCreate,
).toEqual([
expect.objectContaining({
universalIdentifier: getViewFieldUniversalIdentifier({
applicationUniversalIdentifier:
universalIdentifier: getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: FIELD_UNIVERSAL_IDENTIFIER,
@@ -241,8 +241,8 @@ describe('DemoteAndBackfillApplicationIndexViewCommand', () => {
],
viewFields: [
{
universalIdentifier: getViewFieldUniversalIdentifier({
applicationUniversalIdentifier:
universalIdentifier: getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: FIELD_UNIVERSAL_IDENTIFIER,
@@ -282,8 +282,8 @@ describe('DemoteAndBackfillApplicationIndexViewCommand', () => {
payload.allFlatEntityOperationByMetadataName.viewField.flatEntityToCreate,
).toEqual([
expect.objectContaining({
universalIdentifier: getViewFieldUniversalIdentifier({
applicationUniversalIdentifier:
universalIdentifier: getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
EXTERNAL_APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier: FIELD_UNIVERSAL_IDENTIFIER,
@@ -1,7 +1,7 @@
import {
getFieldUniversalIdentifier,
getSystemViewFieldUniversalIdentifier,
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { FieldMetadataType, ViewKey } from 'twenty-shared/types';
@@ -25,7 +25,8 @@ const PRIORITY_FIELD_UNIVERSAL_IDENTIFIER =
const DERIVED_INDEX_VIEW_UNIVERSAL_IDENTIFIER =
getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier:
APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
@@ -37,8 +38,9 @@ const computeViewFieldUniversalIdentifier = ({
viewUniversalIdentifier: string;
fieldMetadataUniversalIdentifier: string;
}) =>
getViewFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier,
fieldMetadataUniversalIdentifier,
});
@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common';
import {
getSystemViewFieldUniversalIdentifier,
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { ViewKey } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -56,7 +56,7 @@ export class FieldIndexViewFieldOnCreateSideEffectHandlerService extends Metadat
}
const indexViewUniversalIdentifier = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier:
objectMetadataApplicationUniversalIdentifier:
parentFlatObjectMetadata.applicationUniversalIdentifier,
objectUniversalIdentifier: objectMetadataUniversalIdentifier,
viewKey: ViewKey.INDEX,
@@ -255,8 +255,9 @@ export class FieldIndexViewFieldOnCreateSideEffectHandlerService extends Metadat
const { applicationUniversalIdentifier } = sourceFlatFieldMetadata;
return {
universalIdentifier: getViewFieldUniversalIdentifier({
applicationUniversalIdentifier,
universalIdentifier: getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
applicationUniversalIdentifier,
viewUniversalIdentifier: indexViewUniversalIdentifier,
fieldMetadataUniversalIdentifier:
sourceFlatFieldMetadata.universalIdentifier,
@@ -10,7 +10,8 @@ const NAME_FIELD_UNIVERSAL_IDENTIFIER = 'd1d2d3d4-d5d6-4000-8000-000000000001';
const CODE_FIELD_UNIVERSAL_IDENTIFIER = 'd1d2d3d4-d5d6-4000-8000-000000000002';
const INDEX_VIEW_UNIVERSAL_IDENTIFIER = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier:
APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
@@ -1,7 +1,7 @@
import {
getFieldUniversalIdentifier,
getSystemViewFieldUniversalIdentifier,
getSystemViewUniversalIdentifier,
getViewFieldUniversalIdentifier,
} from 'twenty-shared/application';
import { FieldMetadataType, ViewKey } from 'twenty-shared/types';
@@ -46,7 +46,8 @@ const DISPLAYABLE_SYSTEM_FIELD_NAMES = [
const DERIVED_INDEX_VIEW_UNIVERSAL_IDENTIFIER =
getSystemViewUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectMetadataApplicationUniversalIdentifier:
APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
@@ -192,8 +193,9 @@ describe('ObjectSystemFieldsAndIndexViewOnCreateSideEffectHandlerService', () =>
for (const viewField of viewFields) {
expect(viewField.isSystemSideEffect).toBe(true);
expect(viewField.universalIdentifier).toBe(
getViewFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier:
APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: DERIVED_INDEX_VIEW_UNIVERSAL_IDENTIFIER,
fieldMetadataUniversalIdentifier:
viewField.fieldMetadataUniversalIdentifier,
@@ -66,7 +66,7 @@ export class ObjectIndexViewLabelIdentifierOnUpdateSideEffectHandlerService exte
}
const indexViewUniversalIdentifier = getSystemViewUniversalIdentifier({
applicationUniversalIdentifier:
objectMetadataApplicationUniversalIdentifier:
updatedFlatObjectMetadata.applicationUniversalIdentifier,
objectUniversalIdentifier: updatedFlatObjectMetadata.universalIdentifier,
viewKey: ViewKey.INDEX,
@@ -15,7 +15,8 @@ describe('computeFlatIndexViewToCreate', () => {
expect(result.universalIdentifier).toBe(
getSystemViewUniversalIdentifier({
applicationUniversalIdentifier,
objectMetadataApplicationUniversalIdentifier:
applicationUniversalIdentifier,
objectUniversalIdentifier,
viewKey: ViewKey.INDEX,
}),
@@ -43,7 +43,8 @@ export const computeFlatIndexViewToCreate = ({
openRecordIn: ViewOpenRecordIn.SIDE_PANEL,
position: 0,
universalIdentifier: getSystemViewUniversalIdentifier({
applicationUniversalIdentifier,
objectMetadataApplicationUniversalIdentifier:
applicationUniversalIdentifier,
objectUniversalIdentifier: objectMetadata.universalIdentifier,
viewKey: ViewKey.INDEX,
}),