mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 13:37:22 +00:00
Refactor read only object and fields (#13936)
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
parent
bb7cd1baa1
commit
3ef94f6e8c
114 changed files with 1274 additions and 483 deletions
|
|
@ -42,7 +42,7 @@ npx nx g @nx/react:component my-component
|
|||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"options": { "jestConfig": "packages/twenty-front/jest.config.ts" }
|
||||
"options": { "jestConfig": "packages/twenty-front/jest.config.mjs" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -94,7 +94,7 @@
|
|||
"twenty-server:jest",
|
||||
"--",
|
||||
"--config",
|
||||
"./jest.config.ts",
|
||||
"./jest.config.mjs",
|
||||
"${relativeFile}"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/packages/twenty-server",
|
||||
|
|
|
|||
4
nx.json
4
nx.json
|
|
@ -104,7 +104,7 @@
|
|||
],
|
||||
"outputs": ["{projectRoot}/coverage"],
|
||||
"options": {
|
||||
"jestConfig": "{projectRoot}/jest.config.ts",
|
||||
"jestConfig": "{projectRoot}/jest.config.mjs",
|
||||
"coverage": true,
|
||||
"coverageReporters": ["text-summary"],
|
||||
"cacheDirectory": "../../.cache/jest/{projectRoot}"
|
||||
|
|
@ -317,4 +317,4 @@
|
|||
"tui": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { readFileSync } from 'fs';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { pathsToModuleNameMapper, type JestConfigWithTsJest } from 'ts-jest';
|
||||
import { pathsToModuleNameMapper } from 'ts-jest';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
|
|
@ -8,9 +8,12 @@ const __dirname = dirname(__filename);
|
|||
|
||||
const tsConfigPath = resolve(__dirname, './tsconfig.spec.json');
|
||||
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf8'));
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
process.env.TZ = 'GMT';
|
||||
// eslint-disable-next-line no-undef
|
||||
process.env.LC_ALL = 'en_US.UTF-8';
|
||||
const jestConfig: JestConfigWithTsJest = {
|
||||
const jestConfig = {
|
||||
silent: true,
|
||||
// For more information please have a look to official docs https://jestjs.io/docs/configuration/#prettierpath-string
|
||||
// Prettier v3 will should be supported in jest v30 https://github.com/jestjs/jest/releases/tag/v30.0.0-alpha.1
|
||||
|
|
@ -640,6 +640,7 @@ export type CreateFieldInput = {
|
|||
isNullable?: InputMaybe<Scalars['Boolean']>;
|
||||
isRemoteCreation?: InputMaybe<Scalars['Boolean']>;
|
||||
isSystem?: InputMaybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
isUnique?: InputMaybe<Scalars['Boolean']>;
|
||||
label: Scalars['String'];
|
||||
morphRelationsCreationPayload?: InputMaybe<Array<Scalars['JSON']>>;
|
||||
|
|
@ -975,6 +976,7 @@ export type Field = {
|
|||
isLabelSyncedWithName?: Maybe<Scalars['Boolean']>;
|
||||
isNullable?: Maybe<Scalars['Boolean']>;
|
||||
isSystem?: Maybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: Maybe<Scalars['Boolean']>;
|
||||
isUnique?: Maybe<Scalars['Boolean']>;
|
||||
label: Scalars['String'];
|
||||
morphRelations?: Maybe<Array<Relation>>;
|
||||
|
|
@ -1010,6 +1012,7 @@ export type FieldFilter = {
|
|||
isActive?: InputMaybe<BooleanFieldComparison>;
|
||||
isCustom?: InputMaybe<BooleanFieldComparison>;
|
||||
isSystem?: InputMaybe<BooleanFieldComparison>;
|
||||
isUIReadOnly?: InputMaybe<BooleanFieldComparison>;
|
||||
or?: InputMaybe<Array<FieldFilter>>;
|
||||
};
|
||||
|
||||
|
|
@ -2158,6 +2161,7 @@ export type Object = {
|
|||
isRemote: Scalars['Boolean'];
|
||||
isSearchable: Scalars['Boolean'];
|
||||
isSystem: Scalars['Boolean'];
|
||||
isUIReadOnly: Scalars['Boolean'];
|
||||
labelIdentifierFieldMetadataId?: Maybe<Scalars['UUID']>;
|
||||
labelPlural: Scalars['String'];
|
||||
labelSingular: Scalars['String'];
|
||||
|
|
@ -2212,6 +2216,7 @@ export type ObjectFilter = {
|
|||
isRemote?: InputMaybe<BooleanFieldComparison>;
|
||||
isSearchable?: InputMaybe<BooleanFieldComparison>;
|
||||
isSystem?: InputMaybe<BooleanFieldComparison>;
|
||||
isUIReadOnly?: InputMaybe<BooleanFieldComparison>;
|
||||
or?: InputMaybe<Array<ObjectFilter>>;
|
||||
};
|
||||
|
||||
|
|
@ -3200,6 +3205,7 @@ export type UpdateFieldInput = {
|
|||
isLabelSyncedWithName?: InputMaybe<Scalars['Boolean']>;
|
||||
isNullable?: InputMaybe<Scalars['Boolean']>;
|
||||
isSystem?: InputMaybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
isUnique?: InputMaybe<Scalars['Boolean']>;
|
||||
label?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
|
|
@ -4226,7 +4232,7 @@ export type DeleteOneFieldMetadataItemMutation = { __typename?: 'Mutation', dele
|
|||
export type ObjectMetadataItemsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'ObjectEdge', node: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
|
||||
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'ObjectEdge', node: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array<Array<string>> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
|
||||
|
||||
export type SkipBookOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
|
@ -7601,6 +7607,7 @@ export const ObjectMetadataItemsDocument = gql`
|
|||
isRemote
|
||||
isActive
|
||||
isSystem
|
||||
isUIReadOnly
|
||||
createdAt
|
||||
updatedAt
|
||||
labelIdentifierFieldMetadataId
|
||||
|
|
@ -7636,6 +7643,7 @@ export const ObjectMetadataItemsDocument = gql`
|
|||
isCustom
|
||||
isActive
|
||||
isSystem
|
||||
isUIReadOnly
|
||||
isNullable
|
||||
isUnique
|
||||
createdAt
|
||||
|
|
|
|||
|
|
@ -636,6 +636,7 @@ export type CreateFieldInput = {
|
|||
isNullable?: InputMaybe<Scalars['Boolean']>;
|
||||
isRemoteCreation?: InputMaybe<Scalars['Boolean']>;
|
||||
isSystem?: InputMaybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
isUnique?: InputMaybe<Scalars['Boolean']>;
|
||||
label: Scalars['String'];
|
||||
morphRelationsCreationPayload?: InputMaybe<Array<Scalars['JSON']>>;
|
||||
|
|
@ -939,6 +940,7 @@ export type Field = {
|
|||
isLabelSyncedWithName?: Maybe<Scalars['Boolean']>;
|
||||
isNullable?: Maybe<Scalars['Boolean']>;
|
||||
isSystem?: Maybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: Maybe<Scalars['Boolean']>;
|
||||
isUnique?: Maybe<Scalars['Boolean']>;
|
||||
label: Scalars['String'];
|
||||
morphRelations?: Maybe<Array<Relation>>;
|
||||
|
|
@ -974,6 +976,7 @@ export type FieldFilter = {
|
|||
isActive?: InputMaybe<BooleanFieldComparison>;
|
||||
isCustom?: InputMaybe<BooleanFieldComparison>;
|
||||
isSystem?: InputMaybe<BooleanFieldComparison>;
|
||||
isUIReadOnly?: InputMaybe<BooleanFieldComparison>;
|
||||
or?: InputMaybe<Array<FieldFilter>>;
|
||||
};
|
||||
|
||||
|
|
@ -2069,6 +2072,7 @@ export type Object = {
|
|||
isRemote: Scalars['Boolean'];
|
||||
isSearchable: Scalars['Boolean'];
|
||||
isSystem: Scalars['Boolean'];
|
||||
isUIReadOnly: Scalars['Boolean'];
|
||||
labelIdentifierFieldMetadataId?: Maybe<Scalars['UUID']>;
|
||||
labelPlural: Scalars['String'];
|
||||
labelSingular: Scalars['String'];
|
||||
|
|
@ -2123,6 +2127,7 @@ export type ObjectFilter = {
|
|||
isRemote?: InputMaybe<BooleanFieldComparison>;
|
||||
isSearchable?: InputMaybe<BooleanFieldComparison>;
|
||||
isSystem?: InputMaybe<BooleanFieldComparison>;
|
||||
isUIReadOnly?: InputMaybe<BooleanFieldComparison>;
|
||||
or?: InputMaybe<Array<ObjectFilter>>;
|
||||
};
|
||||
|
||||
|
|
@ -3046,6 +3051,7 @@ export type UpdateFieldInput = {
|
|||
isLabelSyncedWithName?: InputMaybe<Scalars['Boolean']>;
|
||||
isNullable?: InputMaybe<Scalars['Boolean']>;
|
||||
isSystem?: InputMaybe<Scalars['Boolean']>;
|
||||
isUIReadOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
isUnique?: InputMaybe<Scalars['Boolean']>;
|
||||
label?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
|||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||
import { isRecordReadOnly } from '@/object-record/read-only/utils/isRecordReadOnly';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import React from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
|
@ -81,11 +81,19 @@ export const useRelatedRecordActions = ({
|
|||
selectedRecord,
|
||||
objectPermissions,
|
||||
getTargetObjectWritePermission,
|
||||
objectMetadataItem,
|
||||
}) =>
|
||||
(isDefined(selectedRecord) &&
|
||||
!selectedRecord.isRemote &&
|
||||
isDefined(objectMetadataItem) &&
|
||||
isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: objectPermissions.canUpdateObjectRecords,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
},
|
||||
objectMetadataItem,
|
||||
isRecordDeleted: isDefined(selectedRecord.deletedAt),
|
||||
}) &&
|
||||
objectPermissions.canUpdateObjectRecords &&
|
||||
!isWorkflowSubObjectMetadata(targetObjectNameSingular) &&
|
||||
getTargetObjectWritePermission(
|
||||
targetObjectNameSingular === CoreObjectNameSingular.TaskTarget
|
||||
? CoreObjectNameSingular.Task
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||
|
|
@ -16,6 +15,7 @@ import { Chip, ChipAccent, ChipSize, ChipVariant } from 'twenty-ui/components';
|
|||
import { IconCalendarEvent } from 'twenty-ui/display';
|
||||
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
|
||||
type CalendarEventDetailsProps = {
|
||||
calendarEvent: CalendarEvent;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords
|
|||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsRecordFieldReadOnly';
|
||||
import { isTitleCellInEditModeComponentState } from '@/object-record/record-title-cell/states/isTitleCellInEditModeComponentState';
|
||||
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
|
||||
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql`
|
|||
isRemote
|
||||
isActive
|
||||
isSystem
|
||||
isUIReadOnly
|
||||
createdAt
|
||||
updatedAt
|
||||
labelIdentifierFieldMetadataId
|
||||
|
|
@ -51,6 +52,7 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql`
|
|||
isCustom
|
||||
isActive
|
||||
isSystem
|
||||
isUIReadOnly
|
||||
isNullable
|
||||
isUnique
|
||||
createdAt
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { isWorkflowRelatedObjectMetadata } from '@/object-metadata/utils/isWorkflowRelatedObjectMetadata';
|
||||
|
||||
describe('isWorkflowRelatedObjectMetadata', () => {
|
||||
it('should return true for Workflow object', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata(
|
||||
CoreObjectNameSingular.Workflow,
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for WorkflowVersion object', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata(
|
||||
CoreObjectNameSingular.WorkflowVersion,
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for WorkflowRun object', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata(
|
||||
CoreObjectNameSingular.WorkflowRun,
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for non-workflow related objects', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata(
|
||||
CoreObjectNameSingular.Company,
|
||||
);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for unknown object names', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata('unknownObject');
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for Person object', () => {
|
||||
const result = isWorkflowRelatedObjectMetadata(
|
||||
CoreObjectNameSingular.Person,
|
||||
);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -49,6 +49,7 @@ export const formatFieldMetadataItemAsFieldDefinition = ({
|
|||
settings: field.settings,
|
||||
isNullable: field.isNullable,
|
||||
isCustom: field.isCustom ?? false,
|
||||
isUIReadOnly: field.isUIReadOnly ?? false,
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||
|
||||
export const isObjectMetadataReadOnly = (
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'isRemote' | 'nameSingular'>,
|
||||
) =>
|
||||
objectMetadataItem.isRemote ||
|
||||
isWorkflowSubObjectMetadata(objectMetadataItem.nameSingular);
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||
|
||||
export const isWorkflowRelatedObjectMetadata = (objectNameSingular: string) => {
|
||||
return (
|
||||
objectNameSingular === CoreObjectNameSingular.Workflow ||
|
||||
isWorkflowSubObjectMetadata(objectNameSingular)
|
||||
);
|
||||
};
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
|
||||
export const isWorkflowSubObjectMetadata = (
|
||||
objectMetadataNameSingular?: string,
|
||||
) =>
|
||||
objectMetadataNameSingular === CoreObjectNameSingular.WorkflowVersion ||
|
||||
objectMetadataNameSingular === CoreObjectNameSingular.WorkflowRun;
|
||||
|
|
@ -19,6 +19,7 @@ export const fieldMetadataItemSchema = (existingLabels?: string[]) => {
|
|||
isNullable: z.boolean(),
|
||||
isUnique: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
isUIReadOnly: z.boolean(),
|
||||
label: metadataLabelSchema(existingLabels),
|
||||
isLabelSyncedWithName: z.boolean(),
|
||||
name: camelCaseStringSchema,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const objectMetadataItemSchema = z.object({
|
|||
isCustom: z.boolean(),
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
isUIReadOnly: z.boolean(),
|
||||
isSearchable: z.boolean(),
|
||||
labelIdentifierFieldMetadataId: z.string().uuid(),
|
||||
labelPlural: metadataLabelSchema(),
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ const mockObjectMetadataItem: ObjectMetadataItem = {
|
|||
isLabelSyncedWithName: true,
|
||||
isRemote: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
};
|
||||
|
||||
const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const objectMetadataItemWithPositionField: ObjectMetadataItem = {
|
|||
icon: 'icon',
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isCustom: false,
|
||||
isRemote: false,
|
||||
isSearchable: false,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
|
||||
export type UseFieldIsReadOnlyParams = {
|
||||
fieldMetadataId: string;
|
||||
|
|
@ -42,10 +42,6 @@ export const useIsRecordFieldReadOnly = ({
|
|||
return isRecordFieldReadOnly({
|
||||
isRecordReadOnly,
|
||||
objectPermissions,
|
||||
fieldMetadataId,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
fieldType: fieldMetadataItem.type,
|
||||
isCustom: fieldMetadataItem.isCustom ?? false,
|
||||
fieldMetadataItem,
|
||||
});
|
||||
};
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { isRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordReadOnly';
|
||||
import { isRecordReadOnly } from '@/object-record/read-only/utils/isRecordReadOnly';
|
||||
import { useIsRecordDeleted } from '@/object-record/record-field/ui/hooks/useIsRecordDeleted';
|
||||
|
||||
type UseIsRecordReadOnlyParams = {
|
||||
|
|
@ -12,6 +13,10 @@ export const useIsRecordReadOnly = ({
|
|||
recordId,
|
||||
objectMetadataId,
|
||||
}: UseIsRecordReadOnlyParams) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItemById({
|
||||
objectId: objectMetadataId,
|
||||
});
|
||||
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
const objectPermissions = getObjectPermissionsForObject(
|
||||
|
|
@ -24,5 +29,6 @@ export const useIsRecordReadOnly = ({
|
|||
return isRecordReadOnly({
|
||||
objectPermissions,
|
||||
isRecordDeleted,
|
||||
objectMetadataItem,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
|
||||
describe('isObjectMetadataReadOnly', () => {
|
||||
it('should return false if object can be updated and is not UI read only and is not remote', () => {
|
||||
const result = isObjectMetadataReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
restrictedFields: {},
|
||||
},
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if object cannot be updated and is not UI read only and is not remote', () => {
|
||||
const result = isObjectMetadataReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
restrictedFields: {},
|
||||
},
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if object metadata is UI read only', () => {
|
||||
const result = isObjectMetadataReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
restrictedFields: {},
|
||||
},
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: true,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if object metadata is remote', () => {
|
||||
const result = isObjectMetadataReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
restrictedFields: {},
|
||||
},
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
describe('isRecordFieldReadOnly', () => {
|
||||
|
|
@ -12,16 +12,18 @@ describe('isRecordFieldReadOnly', () => {
|
|||
isRecordReadOnly: false,
|
||||
objectPermissions: mockObjectPermissions,
|
||||
fieldMetadataId: 'field-123',
|
||||
objectNameSingular: 'person',
|
||||
fieldName: 'firstName',
|
||||
fieldType: FieldMetadataType.TEXT,
|
||||
isCustom: false,
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
isUIReadOnly: false,
|
||||
};
|
||||
|
||||
it('should return true when record is read-only', () => {
|
||||
const result = isRecordFieldReadOnly({
|
||||
...mockParams,
|
||||
isRecordReadOnly: true,
|
||||
fieldMetadataItem: {
|
||||
id: 'field-123',
|
||||
isUIReadOnly: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
|
|
@ -34,6 +36,10 @@ describe('isRecordFieldReadOnly', () => {
|
|||
...mockObjectPermissions,
|
||||
canUpdateObjectRecords: false,
|
||||
},
|
||||
fieldMetadataItem: {
|
||||
id: 'field-123',
|
||||
isUIReadOnly: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
|
|
@ -48,36 +54,22 @@ describe('isRecordFieldReadOnly', () => {
|
|||
'field-123': { canUpdate: false },
|
||||
},
|
||||
},
|
||||
fieldMetadataItem: {
|
||||
id: 'field-123',
|
||||
isUIReadOnly: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for system read-only fields like createdAt', () => {
|
||||
it('should return true when field is marked as UI read-only', () => {
|
||||
const result = isRecordFieldReadOnly({
|
||||
...mockParams,
|
||||
fieldName: 'createdAt',
|
||||
fieldType: FieldMetadataType.DATE_TIME,
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for calendar event objects (system read-only)', () => {
|
||||
const result = isRecordFieldReadOnly({
|
||||
...mockParams,
|
||||
objectNameSingular: 'calendarEvent',
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for workflow non-name fields (system read-only)', () => {
|
||||
const result = isRecordFieldReadOnly({
|
||||
...mockParams,
|
||||
objectNameSingular: 'workflow',
|
||||
fieldName: 'status',
|
||||
isCustom: false,
|
||||
fieldMetadataItem: {
|
||||
id: 'field-123',
|
||||
isUIReadOnly: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
|
|
@ -86,6 +78,10 @@ describe('isRecordFieldReadOnly', () => {
|
|||
it('should return false when all conditions allow editing', () => {
|
||||
const result = isRecordFieldReadOnly({
|
||||
...mockParams,
|
||||
fieldMetadataItem: {
|
||||
id: 'field-123',
|
||||
isUIReadOnly: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import { isRecordReadOnly } from '@/object-record/read-only/utils/isRecordReadOnly';
|
||||
|
||||
describe('isRecordReadOnly', () => {
|
||||
it('should return false if record is not deleted, has update permissions and object metadata is not read only', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: false,
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if record is not deleted but lacks update permissions and object metadata is not read only', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: false,
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if record is deleted even with update permissions and object metadata is not read only', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: true,
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if record is not deleted and has update permissions but object metadata is UI read only', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: true,
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: true,
|
||||
isRemote: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if record is not deleted and has update permissions but object metadata is remote', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: false,
|
||||
objectMetadataItem: {
|
||||
isUIReadOnly: false,
|
||||
isRemote: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsFieldMetadataReadOnlyByPermissionParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
fieldMetadataId: string;
|
||||
};
|
||||
|
||||
export const isFieldMetadataReadOnlyByPermissions = ({
|
||||
objectPermissions,
|
||||
fieldMetadataId,
|
||||
}: IsFieldMetadataReadOnlyByPermissionParams) => {
|
||||
if (objectPermissions.canUpdateObjectRecords === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const fieldMetadataIsRestrictedForUpdate =
|
||||
objectPermissions.restrictedFields?.[fieldMetadataId]?.canUpdate === false;
|
||||
|
||||
return fieldMetadataIsRestrictedForUpdate;
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isFieldMetadataReadOnlyByPermissions } from '@/object-record/read-only/utils/internal/isFieldMetadataReadOnlyByPermissions';
|
||||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsFieldMetadataReadOnlyParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'isUIReadOnly' | 'isRemote'>;
|
||||
fieldMetadataItem: Pick<FieldMetadataItem, 'id' | 'isUIReadOnly'>;
|
||||
};
|
||||
|
||||
export const isFieldMetadataReadOnly = ({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
fieldMetadataItem,
|
||||
}: IsFieldMetadataReadOnlyParams) => {
|
||||
const objectMetadataReadOnly = isObjectMetadataReadOnly({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const fieldReadOnlyByPermissions = isFieldMetadataReadOnlyByPermissions({
|
||||
objectPermissions,
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
});
|
||||
|
||||
return (
|
||||
objectMetadataReadOnly ||
|
||||
fieldMetadataItem.isUIReadOnly ||
|
||||
fieldReadOnlyByPermissions
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsObjectMetadataReadOnlyParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'isUIReadOnly' | 'isRemote'>;
|
||||
};
|
||||
|
||||
export const isObjectMetadataReadOnly = ({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
}: IsObjectMetadataReadOnlyParams) => {
|
||||
return (
|
||||
!objectPermissions.canUpdateObjectRecords ||
|
||||
objectMetadataItem.isUIReadOnly ||
|
||||
objectMetadataItem.isRemote
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { isFieldMetadataReadOnlyByPermissions } from '@/object-record/read-only/utils/internal/isFieldMetadataReadOnlyByPermissions';
|
||||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsRecordFieldReadOnlyParams = {
|
||||
isRecordReadOnly: boolean;
|
||||
fieldMetadataItem: Pick<FieldMetadataItem, 'id' | 'isUIReadOnly'>;
|
||||
objectPermissions: ObjectPermission;
|
||||
};
|
||||
|
||||
export const isRecordFieldReadOnly = ({
|
||||
objectPermissions,
|
||||
isRecordReadOnly,
|
||||
fieldMetadataItem,
|
||||
}: IsRecordFieldReadOnlyParams) => {
|
||||
const fieldReadOnlyByPermissions = isFieldMetadataReadOnlyByPermissions({
|
||||
objectPermissions,
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
});
|
||||
|
||||
return (
|
||||
isRecordReadOnly ||
|
||||
fieldMetadataItem.isUIReadOnly ||
|
||||
fieldReadOnlyByPermissions
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
export type IsObjectReadOnlyParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'isUIReadOnly' | 'isRemote'>;
|
||||
isRecordDeleted: boolean;
|
||||
};
|
||||
|
||||
export const isRecordReadOnly = ({
|
||||
objectPermissions,
|
||||
isRecordDeleted,
|
||||
objectMetadataItem,
|
||||
}: IsObjectReadOnlyParams) => {
|
||||
return (
|
||||
isRecordDeleted ||
|
||||
isObjectMetadataReadOnly({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { RecordBoardCardBodyContainer } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBodyContainer';
|
||||
import { StopPropagationContainer } from '@/object-record/record-board/record-board-card/components/StopPropagationContainer';
|
||||
|
|
@ -10,7 +11,6 @@ import {
|
|||
type RecordUpdateHook,
|
||||
type RecordUpdateHookParams,
|
||||
} from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { getFieldButtonIcon } from '@/object-record/record-field/ui/utils/getFieldButtonIcon';
|
||||
|
|
@ -45,12 +45,10 @@ export const RecordBoardCardBody = ({
|
|||
isRecordFieldReadOnly: isRecordFieldReadOnly({
|
||||
isRecordReadOnly,
|
||||
objectPermissions,
|
||||
fieldMetadataId: fieldDefinition.fieldMetadataId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
fieldType: fieldDefinition.type,
|
||||
isCustom: fieldDefinition.metadata.isCustom,
|
||||
objectNameSingular:
|
||||
fieldDefinition.metadata.objectMetadataNameSingular ?? '',
|
||||
fieldMetadataItem: {
|
||||
id: fieldDefinition.fieldMetadataId,
|
||||
isUIReadOnly: fieldDefinition.metadata.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import styled from '@emotion/styled';
|
|||
import { Draggable } from '@hello-pangea/dnd';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
|
||||
import { RecordBoardCardHotkeysEffect } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHotkeysEffect';
|
||||
|
|
@ -9,7 +10,6 @@ import { RecordBoardCardMultiDragPreview } from '@/object-record/record-board/re
|
|||
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue';
|
||||
|
||||
const StyledDraggableContainer = styled.div`
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ describe('buildRecordGqlFieldsAggregateForView', () => {
|
|||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isRemote: false,
|
||||
isSearchable: false,
|
||||
labelIdentifierFieldMetadataId: '06b33746-5293-4d07-9f7f-ebf5ad396064',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { RecordFieldListCellEditModePortal } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortal';
|
||||
import { RecordFieldListCellHoveredPortal } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortal';
|
||||
import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems';
|
||||
|
|
@ -11,8 +13,6 @@ import { RecordDetailRelationSection } from '@/object-record/record-field-list/r
|
|||
import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext';
|
||||
import { recordFieldListHoverPositionComponentState } from '@/object-record/record-field-list/states/recordFieldListHoverPositionComponentState';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||
|
|
@ -123,11 +123,10 @@ export const RecordFieldList = ({
|
|||
objectPermissionsByObjectMetadataId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
}),
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
objectNameSingular,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
fieldType: fieldMetadataItem.type,
|
||||
isCustom: fieldMetadataItem.isCustom ?? false,
|
||||
fieldMetadataItem: {
|
||||
id: fieldMetadataItem.id,
|
||||
isUIReadOnly: fieldMetadataItem.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
}}
|
||||
>
|
||||
|
|
@ -172,11 +171,10 @@ export const RecordFieldList = ({
|
|||
objectPermissionsByObjectMetadataId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
}),
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
objectNameSingular,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
fieldType: fieldMetadataItem.type,
|
||||
isCustom: fieldMetadataItem.isCustom ?? false,
|
||||
fieldMetadataItem: {
|
||||
id: fieldMetadataItem.id,
|
||||
isUIReadOnly: fieldMetadataItem.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
onMouseEnter: () =>
|
||||
handleMouseEnter(
|
||||
|
|
@ -233,11 +231,10 @@ export const RecordFieldList = ({
|
|||
objectPermissionsByObjectMetadataId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
}),
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
objectNameSingular,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
fieldType: fieldMetadataItem.type,
|
||||
isCustom: fieldMetadataItem.isCustom ?? false,
|
||||
fieldMetadataItem: {
|
||||
id: fieldMetadataItem.id,
|
||||
isUIReadOnly: fieldMetadataItem.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useContext } from 'react';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { RecordDetailRelationSectionDropdownToMany } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany';
|
||||
import { RecordDetailRelationSectionDropdownToOne } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { type FieldRelationMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsRecordFieldReadOnly';
|
||||
import {
|
||||
FieldContext,
|
||||
type RecordUpdateHook,
|
||||
type RecordUpdateHookParams,
|
||||
} from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
export const FieldContextProvider = ({
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
import { isObjectReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isObjectReadOnly';
|
||||
|
||||
describe('isObjectReadOnly', () => {
|
||||
it('should return true if object is not read only', () => {
|
||||
const result = isObjectReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if object is read only', () => {
|
||||
const result = isObjectReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import { isRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordReadOnly';
|
||||
|
||||
describe('isRecordReadOnly', () => {
|
||||
it('should return false if record is not deleted and has update permissions', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: false,
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if record is not deleted but lacks update permissions', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: false,
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if record is deleted even with update permissions', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: true,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: true,
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if record is deleted and lacks update permissions', () => {
|
||||
const result = isRecordReadOnly({
|
||||
objectPermissions: {
|
||||
canUpdateObjectRecords: false,
|
||||
objectMetadataId: '123',
|
||||
},
|
||||
isRecordDeleted: true,
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import { isObjectReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isObjectReadOnly';
|
||||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
export type IsFieldReadOnlyByPermissionParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
fieldMetadataId: string;
|
||||
};
|
||||
|
||||
export const isFieldReadOnlyByPermissions = ({
|
||||
objectPermissions,
|
||||
fieldMetadataId,
|
||||
}: IsFieldReadOnlyByPermissionParams) => {
|
||||
if (isObjectReadOnly({ objectPermissions }) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const fieldMetadataIsRestrictedForUpdate =
|
||||
objectPermissions.restrictedFields[fieldMetadataId]?.canUpdate === false;
|
||||
|
||||
return fieldMetadataIsRestrictedForUpdate;
|
||||
};
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||
import { isWorkflowRunJsonField } from '@/object-record/record-field/ui/meta-types/utils/isWorkflowRunJsonField';
|
||||
import { isFieldActor } from '@/object-record/record-field/ui/types/guards/isFieldActor';
|
||||
import { isFieldRichText } from '@/object-record/record-field/ui/types/guards/isFieldRichText';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export type IsFieldReadOnlyBySystemParams = {
|
||||
objectNameSingular: string;
|
||||
fieldName?: string;
|
||||
fieldType?: FieldMetadataType;
|
||||
isCustom?: boolean;
|
||||
};
|
||||
|
||||
export const isFieldReadOnlyBySystem = ({
|
||||
objectNameSingular,
|
||||
fieldName,
|
||||
fieldType,
|
||||
isCustom,
|
||||
}: IsFieldReadOnlyBySystemParams) => {
|
||||
if (
|
||||
isWorkflowRunJsonField({
|
||||
objectMetadataNameSingular: objectNameSingular,
|
||||
fieldName,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isWorkflowSubObjectMetadata(objectNameSingular) && !isCustom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (objectNameSingular === CoreObjectNameSingular.CalendarEvent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
objectNameSingular === CoreObjectNameSingular.Workflow &&
|
||||
fieldName !== 'name' &&
|
||||
!isCustom
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
objectNameSingular !== CoreObjectNameSingular.Note &&
|
||||
fieldName === 'noteTargets'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
objectNameSingular !== CoreObjectNameSingular.Task &&
|
||||
fieldName === 'taskTargets'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isFieldDateOrDateTime =
|
||||
fieldType === FieldMetadataType.DATE ||
|
||||
fieldType === FieldMetadataType.DATE_TIME;
|
||||
const isFieldCreatedAtOrUpdatedAt =
|
||||
fieldName === 'createdAt' || fieldName === 'updatedAt';
|
||||
|
||||
if (isFieldDateOrDateTime && isFieldCreatedAtOrUpdatedAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(fieldType) &&
|
||||
(isFieldActor({ type: fieldType }) || isFieldRichText({ type: fieldType }))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsObjectReadOnlyParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
};
|
||||
|
||||
export const isObjectReadOnly = ({
|
||||
objectPermissions,
|
||||
}: IsObjectReadOnlyParams) => {
|
||||
return !objectPermissions.canUpdateObjectRecords;
|
||||
};
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import {
|
||||
isFieldReadOnlyByPermissions,
|
||||
type IsFieldReadOnlyByPermissionParams,
|
||||
} from '@/object-record/record-field/ui/hooks/read-only/utils/internal/isFieldReadOnlyByPermissions';
|
||||
import {
|
||||
isFieldReadOnlyBySystem,
|
||||
type IsFieldReadOnlyBySystemParams,
|
||||
} from '@/object-record/record-field/ui/hooks/read-only/utils/internal/isFieldReadOnlyBySystem';
|
||||
|
||||
type IsRecordFieldReadOnlyParams = {
|
||||
isRecordReadOnly: boolean;
|
||||
} & IsFieldReadOnlyByPermissionParams &
|
||||
IsFieldReadOnlyBySystemParams;
|
||||
|
||||
export const isRecordFieldReadOnly = ({
|
||||
isRecordReadOnly,
|
||||
objectPermissions,
|
||||
fieldMetadataId,
|
||||
objectNameSingular,
|
||||
fieldName,
|
||||
fieldType,
|
||||
isCustom,
|
||||
}: IsRecordFieldReadOnlyParams) => {
|
||||
const fieldReadOnlyByPermissions = isFieldReadOnlyByPermissions({
|
||||
objectPermissions,
|
||||
fieldMetadataId,
|
||||
});
|
||||
|
||||
const fieldReadOnlyBySystem = isFieldReadOnlyBySystem({
|
||||
objectNameSingular,
|
||||
fieldName,
|
||||
fieldType,
|
||||
isCustom,
|
||||
});
|
||||
|
||||
return (
|
||||
isRecordReadOnly || fieldReadOnlyByPermissions || fieldReadOnlyBySystem
|
||||
);
|
||||
};
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { type ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
type IsObjectReadOnlyParams = {
|
||||
objectPermissions: ObjectPermission;
|
||||
isRecordDeleted: boolean;
|
||||
};
|
||||
|
||||
export const isRecordReadOnly = ({
|
||||
objectPermissions,
|
||||
isRecordDeleted,
|
||||
}: IsObjectReadOnlyParams) => {
|
||||
return isRecordDeleted || !objectPermissions.canUpdateObjectRecords;
|
||||
};
|
||||
|
|
@ -29,7 +29,6 @@ import { recordStoreFamilySelector } from '@/object-record/record-store/states/s
|
|||
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { isWorkflowRunJsonField } from '@/object-record/record-field/ui/meta-types/utils/isWorkflowRunJsonField';
|
||||
import { isFieldArray } from '@/object-record/record-field/ui/types/guards/isFieldArray';
|
||||
import { isFieldArrayValue } from '@/object-record/record-field/ui/types/guards/isFieldArrayValue';
|
||||
import { isFieldRichText } from '@/object-record/record-field/ui/types/guards/isFieldRichText';
|
||||
|
|
@ -143,13 +142,10 @@ export const usePersistField = ({
|
|||
const fieldIsArray =
|
||||
isFieldArray(fieldDefinition) && isFieldArrayValue(valueToPersist);
|
||||
|
||||
const isUnpersistableRawJsonField = isWorkflowRunJsonField({
|
||||
objectMetadataNameSingular:
|
||||
fieldDefinition.metadata.objectMetadataNameSingular,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
const fieldIsUIReadOnly =
|
||||
fieldDefinition.metadata.isUIReadOnly ?? false;
|
||||
|
||||
if (fieldIsRawJson && isUnpersistableRawJsonField) {
|
||||
if (fieldIsRawJson && fieldIsUIReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import styled from '@emotion/styled';
|
||||
|
||||
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
|
||||
import { isWorkflowRunJsonField } from '@/object-record/record-field/ui/meta-types/utils/isWorkflowRunJsonField';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
|
|
@ -142,11 +141,7 @@ export const RawJsonFieldInput = () => {
|
|||
dependencies: [handleShiftTab, draftValue],
|
||||
});
|
||||
|
||||
const showEditingButton = !isWorkflowRunJsonField({
|
||||
objectMetadataNameSingular:
|
||||
fieldDefinition.metadata.objectMetadataNameSingular,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
const showEditingButton = !fieldDefinition.metadata.isUIReadOnly;
|
||||
|
||||
const handleStartEditing = () => {
|
||||
setIsEditing(true);
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
|
||||
// FIXME: This is temporary. We'll soon introduce a new display mode for all fields and we'll have to remove this code.
|
||||
export const isWorkflowRunJsonField = ({
|
||||
objectMetadataNameSingular,
|
||||
fieldName,
|
||||
}: {
|
||||
fieldName: string | undefined;
|
||||
objectMetadataNameSingular: string | undefined;
|
||||
}) => {
|
||||
return (
|
||||
objectMetadataNameSingular === CoreObjectNameSingular.WorkflowRun &&
|
||||
fieldName === 'state'
|
||||
);
|
||||
};
|
||||
|
|
@ -15,4 +15,5 @@ export type FieldDefinition<T extends FieldMetadata> = {
|
|||
infoTooltipContent?: string;
|
||||
defaultValue?: any;
|
||||
editButtonIcon?: IconComponent;
|
||||
isUIReadOnly?: boolean;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ type BaseFieldMetadata = {
|
|||
fieldName: string;
|
||||
objectMetadataNameSingular?: string;
|
||||
isCustom?: boolean;
|
||||
isUIReadOnly?: boolean;
|
||||
};
|
||||
|
||||
export type FieldUuidMetadata = BaseFieldMetadata & {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ const mockObjectMetadataItem: ObjectMetadataItem = {
|
|||
isRemote: false,
|
||||
isSearchable: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
labelIdentifierFieldMetadataId: 'mock-id',
|
||||
labelPlural: 'Tests',
|
||||
labelSingular: 'Test',
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ describe('useRecordData', () => {
|
|||
fieldName: 'updatedAt',
|
||||
isCustom: false,
|
||||
isNullable: false,
|
||||
isUIReadOnly: false,
|
||||
objectMetadataNameSingular: 'person',
|
||||
options: null,
|
||||
placeHolder: 'Last update',
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte
|
|||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsRecordFieldReadOnly';
|
||||
import {
|
||||
FieldContext,
|
||||
type RecordUpdateHook,
|
||||
type RecordUpdateHookParams,
|
||||
} from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { FieldFocusContextProvider } from '@/object-record/record-field/ui/contexts/FieldFocusContextProvider';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RecordInlineCellAnchoredPortalContext } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortalContext';
|
||||
import { RecordInlineCellCloseOnCommandMenuOpeningEffect } from '@/object-record/record-inline-cell/components/RecordInlineCellCloseOnCommandMenuOpeningEffect';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsRecordFieldReadOnly';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
|
||||
import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandard
|
|||
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsRecordFieldReadOnly';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
|
||||
import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions';
|
||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { type IconComponent } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
|
|
@ -35,7 +36,13 @@ export const RecordTableEmptyStateDisplay = (
|
|||
props: RecordTableEmptyStateDisplayProps,
|
||||
) => {
|
||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||
const isReadOnly = isObjectMetadataReadOnly(objectMetadataItem);
|
||||
const objectPermissions = useObjectPermissionsForObject(
|
||||
objectMetadataItem.id,
|
||||
);
|
||||
const isReadOnly = isObjectMetadataReadOnly({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
return (
|
||||
<AnimatedPlaceholderEmptyContainer>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { isFieldRelationFromManyObjects } from '@/object-record/record-field/ui/types/guards/isFieldRelationFromManyObjects';
|
||||
import { isFieldRelationToOneObject } from '@/object-record/record-field/ui/types/guards/isFieldRelationToOneObject';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
|
|
@ -63,11 +63,10 @@ export const RecordTableCellFieldContextGeneric = ({
|
|||
isRecordFieldReadOnly: isRecordFieldReadOnly({
|
||||
isRecordReadOnly: isRecordReadOnly ?? false,
|
||||
objectPermissions,
|
||||
fieldMetadataId: columnDefinition.fieldMetadataId,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
fieldName: columnDefinition.metadata.fieldName,
|
||||
fieldType: columnDefinition.type,
|
||||
isCustom: objectMetadataItem.isCustom,
|
||||
fieldMetadataItem: {
|
||||
id: columnDefinition.fieldMetadataId,
|
||||
isUIReadOnly: columnDefinition.metadata.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
isForbidden: !hasObjectReadPermissions,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isRecordFieldReadOnly';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
|
|
@ -70,13 +70,12 @@ export const RecordTableCellFieldContextLabelIdentifier = ({
|
|||
isLabelIdentifierCompact,
|
||||
displayedMaxRows: 1,
|
||||
isRecordFieldReadOnly: isRecordFieldReadOnly({
|
||||
objectPermissions,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
fieldName: columnDefinition.metadata.fieldName,
|
||||
fieldType: columnDefinition.type,
|
||||
isCustom: objectMetadataItem.isCustom,
|
||||
fieldMetadataId: columnDefinition.fieldMetadataId,
|
||||
isRecordReadOnly: isRecordReadOnly ?? false,
|
||||
objectPermissions,
|
||||
fieldMetadataItem: {
|
||||
id: columnDefinition.fieldMetadataId,
|
||||
isUIReadOnly: columnDefinition.metadata.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
maxWidth: columnDefinition.size,
|
||||
onRecordChipClick: () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import styled from '@emotion/styled';
|
|||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField';
|
||||
import { isObjectReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isObjectReadOnly';
|
||||
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
|
||||
|
|
@ -241,8 +241,9 @@ export const RecordTableHeaderCell = ({
|
|||
createNewIndexRecord();
|
||||
};
|
||||
|
||||
const isReadOnly = isObjectReadOnly({
|
||||
const isReadOnly = isObjectMetadataReadOnly({
|
||||
objectPermissions,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { useIsRecordReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordReadOnly';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ describe('generateAggregateQuery', () => {
|
|||
isLabelSyncedWithName: true,
|
||||
isRemote: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
};
|
||||
|
||||
const mockRecordGqlFields = {
|
||||
|
|
@ -63,6 +64,7 @@ describe('generateAggregateQuery', () => {
|
|||
isLabelSyncedWithName: true,
|
||||
isRemote: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
};
|
||||
|
||||
const mockRecordGqlFields = {
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@ import { useMemo } from 'react';
|
|||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
type FieldPermission,
|
||||
RelationType,
|
||||
} from '~/generated/graphql';
|
||||
import { type FieldPermission, RelationType } from '~/generated/graphql';
|
||||
|
||||
export const StyledObjectFieldTableRow = styled(TableRow)`
|
||||
grid-template-columns: 180px 1fr 60px 60px;
|
||||
|
|
@ -75,21 +71,6 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
|||
const { upsertFieldPermissionInDraftRole } =
|
||||
useUpsertFieldPermissionInDraftRole(roleId);
|
||||
|
||||
const fieldIsCreatedBy =
|
||||
fieldMetadataItem.name === 'createdBy' &&
|
||||
fieldMetadataItem.type === FieldMetadataType.ACTOR;
|
||||
|
||||
const fieldIsDeletedAt =
|
||||
fieldMetadataItem.name === 'deletedAt' &&
|
||||
fieldMetadataItem.type === FieldMetadataType.DATE_TIME;
|
||||
|
||||
const fieldIsLabelIdentifier =
|
||||
fieldMetadataItem.id ===
|
||||
objectMetadataItem.labelIdentifierFieldMetadataId;
|
||||
|
||||
const fieldMustBeReadableAndUpdatable =
|
||||
fieldIsLabelIdentifier || fieldIsCreatedBy || fieldIsDeletedAt;
|
||||
|
||||
const handleSeeChange = () => {
|
||||
if (isDefined(fieldPermissionForThisFieldMetadataItem)) {
|
||||
if (
|
||||
|
|
@ -196,7 +177,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
|||
) : (
|
||||
<TableCell>
|
||||
<OverridableCheckbox
|
||||
disabled={fieldMustBeReadableAndUpdatable ?? false}
|
||||
disabled={fieldMetadataItem.isUIReadOnly ?? false}
|
||||
checked={true}
|
||||
onChange={handleSeeChange}
|
||||
type={isReadRestricted ? 'override' : 'default'}
|
||||
|
|
@ -208,7 +189,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
|||
) : (
|
||||
<TableCell align="left">
|
||||
<OverridableCheckbox
|
||||
disabled={fieldMustBeReadableAndUpdatable ?? false}
|
||||
disabled={fieldMetadataItem.isUIReadOnly ?? false}
|
||||
checked={true}
|
||||
onChange={handleUpdateChange}
|
||||
type={isUpdateRestricted ? 'override' : 'default'}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { isWorkflowRelatedObjectMetadata } from '@/object-metadata/utils/isWorkflowRelatedObjectMetadata';
|
||||
|
||||
export const useObjectMetadataItemsThatCanHavePermission = () => {
|
||||
const { alphaSortedActiveNonSystemObjectMetadataItems: objectMetadataItems } =
|
||||
useFilteredObjectMetadataItems();
|
||||
|
||||
const objectMetadataItemsThatCanHavePermission = objectMetadataItems.filter(
|
||||
(objectMetadataItem) =>
|
||||
!isWorkflowRelatedObjectMetadata(objectMetadataItem.nameSingular),
|
||||
(objectMetadataItem) => !objectMetadataItem.isUIReadOnly,
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export const mapViewFieldsToColumnDefinitions = ({
|
|||
isLabelIdentifier,
|
||||
isVisible: isLabelIdentifier || viewField.isVisible,
|
||||
viewFieldId: viewField.id,
|
||||
isUIReadOnly: correspondingColumnDefinition.metadata.isUIReadOnly,
|
||||
isSortable: correspondingColumnDefinition.isSortable,
|
||||
isFilterable: correspondingColumnDefinition.isFilterable,
|
||||
defaultValue: correspondingColumnDefinition.defaultValue,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const fields = [
|
|||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isNullable: false,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
|
|
@ -38,6 +39,7 @@ const fields = [
|
|||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isNullable: true,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
|
|
@ -51,6 +53,7 @@ const fields = [
|
|||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isNullable: true,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
|
|
@ -66,6 +69,7 @@ const mockObjectMetadataItem: ObjectMetadataItem = {
|
|||
description: 'A company',
|
||||
icon: 'IconBuilding',
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
createdAt: '',
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@
|
|||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"lingui.config.ts",
|
||||
"jest.config.ts",
|
||||
"jest.config.mjs",
|
||||
"vite.config.ts",
|
||||
"setupTests.ts"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"include": [
|
||||
"**/__mocks__/**/*",
|
||||
"jest.config.ts",
|
||||
"jest.config.mjs",
|
||||
"setupTests.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.spec.ts",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddIsUIReadOnlyToFieldMetadata1755000000000
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddIsUIReadOnlyToFieldMetadata1755000000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" ADD "isUIReadOnly" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."objectMetadata" ADD "isUIReadOnly" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" DROP COLUMN "isUIReadOnly"`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."objectMetadata" DROP COLUMN "isUIReadOnly"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +108,11 @@ export class FieldMetadataDTO<T extends FieldMetadataType = FieldMetadataType> {
|
|||
@FilterableField({ nullable: true })
|
||||
isSystem?: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@FilterableField({ nullable: true })
|
||||
isUIReadOnly?: boolean;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@Field({ nullable: true })
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ export class FieldMetadataEntity<
|
|||
@Column({ default: false })
|
||||
isSystem: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
isUIReadOnly: boolean;
|
||||
|
||||
// Is this really nullable ?
|
||||
@Column({ nullable: true, default: true, type: 'boolean' })
|
||||
isNullable: boolean | null;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
|
|||
label: 'flat field metadata label',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isUIReadOnly: false,
|
||||
isLabelSyncedWithName: false,
|
||||
isSystem: false,
|
||||
standardId: null,
|
||||
|
|
|
|||
|
|
@ -53,5 +53,6 @@ export const getDefaultFlatFieldMetadata = ({
|
|||
settings: settings ?? null,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
|
||||
} as const satisfies FlatFieldMetadata;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const getFlatObjectMetadataMock = (
|
|||
isRemote: false,
|
||||
isSearchable: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
labelIdentifierFieldMetadataId: faker.string.uuid(),
|
||||
labelPlural: 'default flat object metadata label plural',
|
||||
labelSingular: 'default flat object metadata label singular',
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
|||
isLabelSyncedWithName: createObjectInput.isLabelSyncedWithName ?? false,
|
||||
isRemote: createObjectInput.isRemote ?? false,
|
||||
isSearchable: true,
|
||||
isUIReadOnly: false,
|
||||
isSystem: false,
|
||||
labelIdentifierFieldMetadataId: baseCustomFlatFieldMetadatas.nameField.id,
|
||||
labelPlural: capitalize(createObjectInput.labelPlural),
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ export class ObjectMetadataDTO {
|
|||
@FilterableField()
|
||||
isSystem: boolean;
|
||||
|
||||
@FilterableField()
|
||||
isUIReadOnly: boolean;
|
||||
|
||||
@FilterableField()
|
||||
isSearchable: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ export class ObjectMetadataEntity implements Required<ObjectMetadataEntity> {
|
|||
@Column({ default: false })
|
||||
isSystem: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
isUIReadOnly: boolean;
|
||||
|
||||
@Column({ default: true })
|
||||
isAuditLogged: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
workspaceId,
|
||||
defaultValue: 'uuid',
|
||||
},
|
||||
|
|
@ -36,6 +37,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isUIReadOnly: false,
|
||||
workspaceId,
|
||||
defaultValue: "'Untitled'",
|
||||
},
|
||||
|
|
@ -50,6 +52,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isUIReadOnly: false,
|
||||
workspaceId,
|
||||
defaultValue: 'now',
|
||||
},
|
||||
|
|
@ -65,6 +68,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
workspaceId,
|
||||
defaultValue: 'now',
|
||||
},
|
||||
|
|
@ -80,6 +84,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
workspaceId,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
|
@ -95,6 +100,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
workspaceId,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
},
|
||||
|
|
@ -110,6 +116,7 @@ export const buildDefaultFieldsForCustomObject = (
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: false,
|
||||
workspaceId,
|
||||
defaultValue: 0,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: 'uuid',
|
||||
|
||||
createdAt,
|
||||
|
|
@ -65,6 +66,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
defaultValue: "'Untitled'",
|
||||
|
||||
createdAt,
|
||||
|
|
@ -95,6 +97,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: 'now',
|
||||
|
||||
createdAt,
|
||||
|
|
@ -125,6 +128,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: 'now',
|
||||
|
||||
createdAt,
|
||||
|
|
@ -155,6 +159,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: null,
|
||||
|
||||
createdAt,
|
||||
|
|
@ -185,6 +190,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
|
||||
createdAt,
|
||||
|
|
@ -215,6 +221,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: 0,
|
||||
|
||||
createdAt,
|
||||
|
|
@ -245,6 +252,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
|||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: null,
|
||||
|
||||
createdAt,
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ const generateSourceFlatFieldMetadata = ({
|
|||
isCustom: false,
|
||||
isLabelSyncedWithName: false,
|
||||
isNullable: true,
|
||||
isUIReadOnly: false,
|
||||
isSystem: true,
|
||||
isUnique: false,
|
||||
label: capitalize(targetFlatObjectMetadata.namePlural),
|
||||
|
|
@ -133,6 +134,7 @@ const generateTargetFlatFieldMetadata = ({
|
|||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isUIReadOnly: false,
|
||||
type: FieldMetadataType.RELATION,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
|
|||
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
|
||||
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsPrimaryField } from 'src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -19,6 +20,7 @@ export abstract class BaseWorkspaceEntity {
|
|||
icon: 'Icon123',
|
||||
})
|
||||
@WorkspaceIsPrimaryField()
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
@WorkspaceIsSystem()
|
||||
id: string;
|
||||
|
||||
|
|
@ -33,6 +35,7 @@ export abstract class BaseWorkspaceEntity {
|
|||
displayFormat: DateDisplayFormat.RELATIVE,
|
||||
},
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdAt: string;
|
||||
|
||||
@WorkspaceField({
|
||||
|
|
@ -46,6 +49,7 @@ export abstract class BaseWorkspaceEntity {
|
|||
displayFormat: DateDisplayFormat.RELATIVE,
|
||||
},
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedAt: string;
|
||||
|
||||
@WorkspaceField({
|
||||
|
|
@ -59,5 +63,6 @@ export abstract class BaseWorkspaceEntity {
|
|||
},
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
deletedAt: string | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity
|
|||
import { WorkspaceCustomEntity } from 'src/engine/twenty-orm/decorators/workspace-custom-entity.decorator';
|
||||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
|
||||
|
|
@ -52,6 +53,7 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
|
|
@ -61,6 +63,7 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
@ -158,6 +161,7 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
})
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
@WorkspaceFieldIndex({ indexType: IndexType.GIN })
|
||||
searchVector: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ export function WorkspaceEntity(
|
|||
'workspace:is-searchable-metadata-args',
|
||||
target,
|
||||
) ?? false;
|
||||
const isUIReadOnly =
|
||||
TypedReflect.getMetadata(
|
||||
'workspace:is-object-ui-readonly-metadata-args',
|
||||
target,
|
||||
) ?? false;
|
||||
|
||||
const objectName = convertClassNameToObjectMetadataName(target.name);
|
||||
|
||||
|
|
@ -60,6 +65,7 @@ export function WorkspaceEntity(
|
|||
shortcut: options.shortcut,
|
||||
isAuditLogged,
|
||||
isSystem,
|
||||
isUIReadOnly,
|
||||
gate,
|
||||
duplicateCriteria,
|
||||
isSearchable,
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ export function WorkspaceField<T extends FieldMetadataType>(
|
|||
object,
|
||||
propertyKey.toString(),
|
||||
) ?? false;
|
||||
const isUIReadOnly =
|
||||
TypedReflect.getMetadata(
|
||||
'workspace:is-field-ui-readonly-metadata-args',
|
||||
object,
|
||||
propertyKey.toString(),
|
||||
) ?? false;
|
||||
const gate = TypedReflect.getMetadata(
|
||||
'workspace:gate-metadata-args',
|
||||
object,
|
||||
|
|
@ -91,6 +97,7 @@ export function WorkspaceField<T extends FieldMetadataType>(
|
|||
isPrimary,
|
||||
isNullable,
|
||||
isSystem,
|
||||
isUIReadOnly,
|
||||
gate,
|
||||
isDeprecated,
|
||||
isUnique,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
|
||||
export function WorkspaceIsFieldUIReadOnly() {
|
||||
return function (target: object, propertyKey?: string | symbol): void {
|
||||
if (propertyKey === undefined) {
|
||||
throw new Error('This decorator should be used with a field not a class');
|
||||
}
|
||||
|
||||
TypedReflect.defineMetadata(
|
||||
'workspace:is-field-ui-readonly-metadata-args',
|
||||
true,
|
||||
target,
|
||||
propertyKey.toString(),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
|
||||
export function WorkspaceIsObjectUIReadOnly() {
|
||||
return function (target: object): void {
|
||||
TypedReflect.defineMetadata(
|
||||
'workspace:is-object-ui-readonly-metadata-args',
|
||||
true,
|
||||
target,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
@ -58,6 +58,12 @@ export function WorkspaceRelation<TClass extends object>(
|
|||
object,
|
||||
propertyKey.toString(),
|
||||
) ?? false;
|
||||
const isUIReadOnly =
|
||||
TypedReflect.getMetadata(
|
||||
'workspace:is-field-ui-readonly-metadata-args',
|
||||
object,
|
||||
propertyKey.toString(),
|
||||
) ?? false;
|
||||
const gate = TypedReflect.getMetadata(
|
||||
'workspace:gate-metadata-args',
|
||||
object,
|
||||
|
|
@ -89,6 +95,7 @@ export function WorkspaceRelation<TClass extends object>(
|
|||
isPrimary,
|
||||
isNullable,
|
||||
isSystem,
|
||||
isUIReadOnly,
|
||||
gate,
|
||||
isLabelSyncedWithName,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ export interface WorkspaceEntityMetadataArgs {
|
|||
*/
|
||||
readonly isSystem: boolean;
|
||||
|
||||
/**
|
||||
* Is UI read-only object.
|
||||
*/
|
||||
readonly isUIReadOnly: boolean;
|
||||
|
||||
/**
|
||||
* Entity gate.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ export interface WorkspaceFieldMetadataArgs {
|
|||
*/
|
||||
readonly isSystem: boolean;
|
||||
|
||||
/**
|
||||
* Is UI read-only field.
|
||||
*/
|
||||
readonly isUIReadOnly: boolean;
|
||||
|
||||
/**
|
||||
* Is nullable field.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ export interface WorkspaceRelationMetadataArgs {
|
|||
*/
|
||||
readonly isSystem: boolean;
|
||||
|
||||
/**
|
||||
* Is UI read-only field.
|
||||
*/
|
||||
readonly isUIReadOnly: boolean;
|
||||
|
||||
/**
|
||||
* Is nullable field.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -66,6 +67,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -95,6 +97,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Rockets",
|
||||
"labelSingular": "Rocket",
|
||||
|
|
@ -115,6 +118,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -152,6 +156,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -181,6 +186,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Rockets",
|
||||
"labelSingular": "Rocket",
|
||||
|
|
@ -201,6 +207,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -230,6 +237,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Pets",
|
||||
"labelSingular": "Pet",
|
||||
|
|
@ -250,6 +258,7 @@ exports[`Workspace migration builder field actions test suite It should build an
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "flat field metadata label",
|
||||
"name": "flatFieldMetadataName",
|
||||
|
|
@ -416,6 +425,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Id",
|
||||
"name": "id",
|
||||
|
|
@ -447,6 +457,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
|
|
@ -478,6 +489,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Creation date",
|
||||
"name": "createdAt",
|
||||
|
|
@ -509,6 +521,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Last update",
|
||||
"name": "updatedAt",
|
||||
|
|
@ -540,6 +553,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Deleted at",
|
||||
"name": "deletedAt",
|
||||
|
|
@ -574,6 +588,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Created by",
|
||||
"name": "createdBy",
|
||||
|
|
@ -605,6 +620,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
|
|
@ -640,6 +656,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -667,6 +684,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TimelineActivities",
|
||||
"name": "timelineActivities",
|
||||
|
|
@ -704,6 +722,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -731,6 +750,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Favorites",
|
||||
"name": "favorites",
|
||||
|
|
@ -768,6 +788,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -795,6 +816,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Attachments",
|
||||
"name": "attachments",
|
||||
|
|
@ -832,6 +854,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -859,6 +882,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "NoteTargets",
|
||||
"name": "noteTargets",
|
||||
|
|
@ -896,6 +920,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -923,6 +948,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TaskTargets",
|
||||
"name": "taskTargets",
|
||||
|
|
@ -956,6 +982,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Search vector",
|
||||
"name": "searchVector",
|
||||
|
|
@ -988,6 +1015,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Rockets",
|
||||
"labelSingular": "Rocket",
|
||||
|
|
@ -1028,6 +1056,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pet",
|
||||
"name": "pet",
|
||||
|
|
@ -1055,6 +1084,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "NoteTargets",
|
||||
"name": "noteTargets",
|
||||
|
|
@ -1088,6 +1118,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Id",
|
||||
"name": "id",
|
||||
|
|
@ -1119,6 +1150,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
|
|
@ -1150,6 +1182,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Creation date",
|
||||
"name": "createdAt",
|
||||
|
|
@ -1181,6 +1214,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Last update",
|
||||
"name": "updatedAt",
|
||||
|
|
@ -1212,6 +1246,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Deleted at",
|
||||
"name": "deletedAt",
|
||||
|
|
@ -1246,6 +1281,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Created by",
|
||||
"name": "createdBy",
|
||||
|
|
@ -1277,6 +1313,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
|
|
@ -1312,6 +1349,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pet",
|
||||
"name": "pet",
|
||||
|
|
@ -1339,6 +1377,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TimelineActivities",
|
||||
"name": "timelineActivities",
|
||||
|
|
@ -1376,6 +1415,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pet",
|
||||
"name": "pet",
|
||||
|
|
@ -1403,6 +1443,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Favorites",
|
||||
"name": "favorites",
|
||||
|
|
@ -1440,6 +1481,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pet",
|
||||
"name": "pet",
|
||||
|
|
@ -1467,6 +1509,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Attachments",
|
||||
"name": "attachments",
|
||||
|
|
@ -1504,6 +1547,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pet",
|
||||
"name": "pet",
|
||||
|
|
@ -1531,6 +1575,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TaskTargets",
|
||||
"name": "taskTargets",
|
||||
|
|
@ -1564,6 +1609,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Search vector",
|
||||
"name": "searchVector",
|
||||
|
|
@ -1595,6 +1641,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Species",
|
||||
"name": "species",
|
||||
|
|
@ -1669,6 +1716,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Traits",
|
||||
"name": "traits",
|
||||
|
|
@ -1743,6 +1791,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Comments",
|
||||
"name": "comments",
|
||||
|
|
@ -1774,6 +1823,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Age",
|
||||
"name": "age",
|
||||
|
|
@ -1814,6 +1864,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Location",
|
||||
"name": "location",
|
||||
|
|
@ -1850,6 +1901,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Vet phone",
|
||||
"name": "vetPhone",
|
||||
|
|
@ -1884,6 +1936,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Vet email",
|
||||
"name": "vetEmail",
|
||||
|
|
@ -1915,6 +1968,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Birthday",
|
||||
"name": "birthday",
|
||||
|
|
@ -1946,6 +2000,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Is good with kids",
|
||||
"name": "isGoodWithKids",
|
||||
|
|
@ -1981,6 +2036,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Pictures",
|
||||
"name": "pictures",
|
||||
|
|
@ -2015,6 +2071,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Average cost of kibble per month",
|
||||
"name": "averageCostOfKibblePerMonth",
|
||||
|
|
@ -2049,6 +2106,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Makes its owner think of",
|
||||
"name": "makesOwnerThinkOf",
|
||||
|
|
@ -2080,6 +2138,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Sound swag (bark style, meow style, etc.)",
|
||||
"name": "soundSwag",
|
||||
|
|
@ -2142,6 +2201,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Bio",
|
||||
"name": "bio",
|
||||
|
|
@ -2173,6 +2233,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Interesting facts",
|
||||
"name": "interestingFacts",
|
||||
|
|
@ -2204,6 +2265,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Extra data",
|
||||
"name": "extraData",
|
||||
|
|
@ -2236,6 +2298,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Pets",
|
||||
"labelSingular": "Pet",
|
||||
|
|
@ -2272,6 +2335,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Id",
|
||||
"name": "id",
|
||||
|
|
@ -2303,6 +2367,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
|
|
@ -2334,6 +2399,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Creation date",
|
||||
"name": "createdAt",
|
||||
|
|
@ -2365,6 +2431,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Last update",
|
||||
"name": "updatedAt",
|
||||
|
|
@ -2396,6 +2463,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Deleted at",
|
||||
"name": "deletedAt",
|
||||
|
|
@ -2430,6 +2498,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Created by",
|
||||
"name": "createdBy",
|
||||
|
|
@ -2461,6 +2530,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": false,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
|
|
@ -2496,6 +2566,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -2523,6 +2594,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TimelineActivities",
|
||||
"name": "timelineActivities",
|
||||
|
|
@ -2560,6 +2632,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -2587,6 +2660,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Favorites",
|
||||
"name": "favorites",
|
||||
|
|
@ -2624,6 +2698,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -2651,6 +2726,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Attachments",
|
||||
"name": "attachments",
|
||||
|
|
@ -2688,6 +2764,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -2715,6 +2792,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "NoteTargets",
|
||||
"name": "noteTargets",
|
||||
|
|
@ -2752,6 +2830,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Rocket",
|
||||
"name": "rocket",
|
||||
|
|
@ -2779,6 +2858,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "TaskTargets",
|
||||
"name": "taskTargets",
|
||||
|
|
@ -2812,6 +2892,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
"label": "Search vector",
|
||||
"name": "searchVector",
|
||||
|
|
@ -2844,6 +2925,7 @@ exports[`Workspace migration builder object actions test suite It should build a
|
|||
"isRemote": false,
|
||||
"isSearchable": true,
|
||||
"isSystem": false,
|
||||
"isUIReadOnly": false,
|
||||
"labelIdentifierFieldMetadataId": Any<String>,
|
||||
"labelPlural": "Rockets",
|
||||
"labelSingular": "Rocket",
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ export class StandardFieldFactory {
|
|||
isCustom: workspaceFieldMetadataArgs.isDeprecated ? true : false,
|
||||
isSystem: workspaceFieldMetadataArgs.isSystem ?? false,
|
||||
isActive: workspaceFieldMetadataArgs.isActive ?? true,
|
||||
isUIReadOnly: workspaceFieldMetadataArgs.isUIReadOnly ?? false,
|
||||
asExpression: workspaceFieldMetadataArgs.asExpression,
|
||||
generatedType: workspaceFieldMetadataArgs.generatedType,
|
||||
isLabelSyncedWithName: workspaceFieldMetadataArgs.isLabelSyncedWithName,
|
||||
|
|
@ -195,6 +196,7 @@ export class StandardFieldFactory {
|
|||
isSystem:
|
||||
workspaceEntityMetadataArgs?.isSystem ||
|
||||
workspaceRelationMetadataArgs.isSystem,
|
||||
isUIReadOnly: workspaceRelationMetadataArgs.isUIReadOnly,
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isActive: workspaceRelationMetadataArgs.isActive ?? true,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export const computeStandardFields = (
|
|||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
isUnique: null,
|
||||
isUIReadOnly: false,
|
||||
options: null,
|
||||
relationTargetFieldMetadata: null,
|
||||
relationTargetFieldMetadataId: null,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
|
|||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsObjectUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-object-ui-readonly.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
|
||||
import { CALENDAR_EVENT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
|
|
@ -30,6 +31,7 @@ import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/co
|
|||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNotAuditLogged()
|
||||
@WorkspaceIsObjectUIReadOnly()
|
||||
export class CalendarEventWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceField({
|
||||
standardId: CALENDAR_EVENT_STANDARD_FIELD_IDS.title,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
|
|||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -157,6 +158,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
// Relations
|
||||
|
|
@ -197,6 +199,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => TaskTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
taskTargets: Relation<TaskTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
@ -208,6 +211,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => NoteTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
noteTargets: Relation<NoteTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity
|
|||
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
|
||||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -86,6 +87,7 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
|
|||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -122,6 +123,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
@ -178,6 +180,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => TaskTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
taskTargets: Relation<TaskTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
@ -189,6 +192,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => NoteTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
noteTargets: Relation<NoteTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
|
|||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -174,6 +175,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
// Relations
|
||||
|
|
@ -214,6 +216,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => TaskTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
taskTargets: Relation<TaskTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
@ -225,6 +228,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
inverseSideTarget: () => NoteTargetWorkspaceEntity,
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
noteTargets: Relation<NoteTargetWorkspaceEntity[]>;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity
|
|||
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
|
||||
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
|
||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
|
|
@ -125,6 +126,7 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
|||
icon: 'IconCreativeCommonsSa',
|
||||
description: msg`The creator of the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-
|
|||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
|
||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
||||
import { WorkspaceIsObjectUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-object-ui-readonly.decorator';
|
||||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
|
||||
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
|
||||
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
|
||||
|
|
@ -80,6 +81,7 @@ export const SEARCH_FIELDS_FOR_WORKFLOW_RUNS: FieldTypeAndNameMetadata[] = [
|
|||
icon: STANDARD_OBJECT_ICONS.workflowRun,
|
||||
})
|
||||
@WorkspaceIsNotAuditLogged()
|
||||
@WorkspaceIsObjectUIReadOnly()
|
||||
export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceField({
|
||||
standardId: WORKFLOW_RUN_STANDARD_FIELD_IDS.name,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue