New field creates fields widget field (#18022)
## Context
Introducing "NewFieldDefaultConfiguration" to FIELDS widget
configurations
```typescript
{
isVisible: boolean;
viewFieldGroupId: string | null;
}
```
This configuration will define where a new field should be added (which
section) and its default visibility inside FIELDS widget views.
The new field position should always be at the end (meaning the last
position for the view fields OR the last position of a viewFieldGroup)
See "New fields" on this screenshot
<img width="401" height="724" alt="Layout V1"
src="https://github.com/user-attachments/assets/4969bcaa-f244-4504-8947-778a02c24c47"
/>
This commit is contained in:
@@ -1617,6 +1617,7 @@ export type FieldRichTextConfiguration = {
|
||||
export type FieldsConfiguration = {
|
||||
__typename?: 'FieldsConfiguration';
|
||||
configurationType: WidgetConfigurationType;
|
||||
newFieldDefaultConfiguration?: Maybe<NewFieldDefaultConfiguration>;
|
||||
viewId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
@@ -3243,6 +3244,12 @@ export type NavigationMenuItem = {
|
||||
viewId?: Maybe<Scalars['UUID']>;
|
||||
};
|
||||
|
||||
export type NewFieldDefaultConfiguration = {
|
||||
__typename?: 'NewFieldDefaultConfiguration';
|
||||
isVisible: Scalars['Boolean'];
|
||||
viewFieldGroupId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type NotesConfiguration = {
|
||||
__typename?: 'NotesConfiguration';
|
||||
configurationType: WidgetConfigurationType;
|
||||
|
||||
+42
@@ -7,6 +7,7 @@ import { type FindOneOptions, type Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { type DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
@@ -24,10 +25,12 @@ import { fromCreateFieldInputToFlatFieldMetadatasToCreate } from 'src/engine/met
|
||||
import { fromDeleteFieldInputToFlatFieldMetadatasToDelete } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-delete-field-input-to-flat-field-metadatas-to-delete.util';
|
||||
import { fromUpdateFieldInputToFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata.util';
|
||||
import { throwOnFieldInputTranspilationsError } from 'src/engine/metadata-modules/flat-field-metadata/utils/throw-on-field-input-transpilations-error.util';
|
||||
import { computeFlatViewFieldsFromFieldsWidgets } from 'src/engine/metadata-modules/flat-view-field/utils/compute-flat-view-fields-from-fields-widgets.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-failure-report.constant';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
|
||||
|
||||
@Injectable()
|
||||
export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntity> {
|
||||
@@ -333,9 +336,19 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
const {
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewMaps: existingFlatViewMaps,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
featureFlagsMap: existingFeatureFlagsMap,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
'flatViewFieldMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
'featureFlagsMap',
|
||||
]);
|
||||
|
||||
const allTranspiledTranspilationInputs: Awaited<
|
||||
@@ -372,6 +385,30 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
{ flatFieldMetadatas: [], indexMetadatas: [] },
|
||||
);
|
||||
|
||||
let flatViewFieldsToCreate: UniversalFlatViewField[] = [];
|
||||
|
||||
if (
|
||||
existingFeatureFlagsMap[
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
|
||||
] ??
|
||||
false
|
||||
) {
|
||||
flatViewFieldsToCreate = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: flatFieldMetadatasToCreate.map((flatFieldMetadata) => ({
|
||||
objectMetadataUniversalIdentifier:
|
||||
flatFieldMetadata.objectMetadataUniversalIdentifier,
|
||||
fieldMetadataUniversalIdentifier:
|
||||
flatFieldMetadata.universalIdentifier,
|
||||
})),
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewMaps: existingFlatViewMaps,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
applicationUniversalIdentifier:
|
||||
resolvedOwnerFlatApplication.universalIdentifier,
|
||||
});
|
||||
}
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
@@ -386,6 +423,11 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: flatViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild,
|
||||
|
||||
+7
-1
@@ -16,7 +16,10 @@ export type FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs =
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatPageLayoutTabMaps' | 'flatObjectMetadataMaps' | 'flatFieldMetadataMaps'
|
||||
| 'flatPageLayoutTabMaps'
|
||||
| 'flatObjectMetadataMaps'
|
||||
| 'flatFieldMetadataMaps'
|
||||
| 'flatViewFieldGroupMaps'
|
||||
>;
|
||||
|
||||
export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
|
||||
@@ -26,6 +29,7 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs): FlatPageLayoutWidget => {
|
||||
const { pageLayoutTabId, ...createPageLayoutWidgetInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
@@ -76,6 +80,8 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
|
||||
configuration: createPageLayoutWidgetInput.configuration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
shouldThrowOnMissingIdentifier: true,
|
||||
}),
|
||||
};
|
||||
|
||||
+37
-1
@@ -42,10 +42,12 @@ const getFieldMetadataUniversalIdentifier = ({
|
||||
export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
configuration,
|
||||
fieldMetadataUniversalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById = {},
|
||||
shouldThrowOnMissingIdentifier = false,
|
||||
}: {
|
||||
configuration: PageLayoutWidgetConfiguration;
|
||||
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
|
||||
viewFieldGroupUniversalIdentifierById?: Partial<Record<string, string>>;
|
||||
shouldThrowOnMissingIdentifier?: boolean;
|
||||
}): UniversalPageLayoutWidgetConfiguration => {
|
||||
switch (configuration.configurationType) {
|
||||
@@ -200,9 +202,43 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
};
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FIELDS: {
|
||||
const { newFieldDefaultConfiguration, ...rest } = configuration;
|
||||
|
||||
if (!isDefined(newFieldDefaultConfiguration)) {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
let viewFieldGroupUniversalIdentifier: string | null = null;
|
||||
|
||||
if (isDefined(newFieldDefaultConfiguration.viewFieldGroupId)) {
|
||||
viewFieldGroupUniversalIdentifier =
|
||||
viewFieldGroupUniversalIdentifierById[
|
||||
newFieldDefaultConfiguration.viewFieldGroupId
|
||||
] ?? null;
|
||||
|
||||
if (
|
||||
!isDefined(viewFieldGroupUniversalIdentifier) &&
|
||||
shouldThrowOnMissingIdentifier
|
||||
) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View field group universal identifier not found for id: ${newFieldDefaultConfiguration.viewFieldGroupId}`,
|
||||
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
newFieldDefaultConfiguration: {
|
||||
isVisible: newFieldDefaultConfiguration.isVisible,
|
||||
viewFieldGroupId: viewFieldGroupUniversalIdentifier,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.VIEW:
|
||||
case WidgetConfigurationType.FIELD:
|
||||
case WidgetConfigurationType.FIELDS:
|
||||
case WidgetConfigurationType.TIMELINE:
|
||||
case WidgetConfigurationType.TASKS:
|
||||
case WidgetConfigurationType.NOTES:
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/type
|
||||
type FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs =
|
||||
FromEntityToFlatEntityArgs<'pageLayoutWidget'> & {
|
||||
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
|
||||
viewFieldGroupUniversalIdentifierById?: Partial<Record<string, string>>;
|
||||
};
|
||||
|
||||
export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
|
||||
@@ -20,6 +21,7 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
|
||||
pageLayoutTabIdToUniversalIdentifierMap,
|
||||
objectMetadataIdToUniversalIdentifierMap,
|
||||
fieldMetadataUniversalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById,
|
||||
}: FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs): FlatPageLayoutWidget => {
|
||||
const pageLayoutWidgetEntityWithoutRelations = removePropertiesFromRecord(
|
||||
pageLayoutWidgetEntity,
|
||||
@@ -70,6 +72,7 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
configuration: pageLayoutWidgetEntityWithoutRelations.configuration,
|
||||
fieldMetadataUniversalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+6
-1
@@ -30,12 +30,15 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
updatePageLayoutWidgetInput: UpdatePageLayoutWidgetInputWithId;
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatObjectMetadataMaps' | 'flatFieldMetadataMaps'
|
||||
| 'flatObjectMetadataMaps'
|
||||
| 'flatFieldMetadataMaps'
|
||||
| 'flatViewFieldGroupMaps'
|
||||
>): FlatPageLayoutWidget => {
|
||||
const { id: pageLayoutWidgetToUpdateId } =
|
||||
extractAndSanitizeObjectStringFields(rawUpdatePageLayoutWidgetInput, [
|
||||
@@ -97,6 +100,8 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
|
||||
configuration: flatPageLayoutWidgetToUpdate.configuration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+743
@@ -0,0 +1,743 @@
|
||||
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/metadata-modules/flat-view-field/constants/default-view-field-size.constant';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
import { computeFlatViewFieldsFromFieldsWidgets } from 'src/engine/metadata-modules/flat-view-field/utils/compute-flat-view-fields-from-fields-widgets.util';
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
|
||||
const APPLICATION_UNIVERSAL_IDENTIFIER = 'app-uid-1';
|
||||
const VIEW_ID = 'view-db-id-1';
|
||||
const VIEW_UNIVERSAL_IDENTIFIER = 'view-uid-1';
|
||||
const VIEW_FIELD_GROUP_ID = 'vfg-db-id-1';
|
||||
const VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIER = 'vfg-uid-1';
|
||||
const OBJECT_METADATA_UNIVERSAL_IDENTIFIER = 'obj-uid-1';
|
||||
|
||||
const buildEmptyFlatEntityMaps = () => ({
|
||||
byUniversalIdentifier: {},
|
||||
universalIdentifierById: {},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
});
|
||||
|
||||
const buildFlatViewMaps = (
|
||||
entries: { id: string; universalIdentifier: string }[] = [],
|
||||
): FlatViewMaps =>
|
||||
({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
entries.map((entry) => [
|
||||
entry.universalIdentifier,
|
||||
{ universalIdentifier: entry.universalIdentifier, id: entry.id },
|
||||
]),
|
||||
),
|
||||
universalIdentifierById: Object.fromEntries(
|
||||
entries.map((entry) => [entry.id, entry.universalIdentifier]),
|
||||
),
|
||||
universalIdentifiersByApplicationId: {},
|
||||
}) as unknown as FlatViewMaps;
|
||||
|
||||
const buildFlatViewFieldGroupMaps = (
|
||||
entries: { id: string; universalIdentifier: string }[] = [],
|
||||
): FlatViewFieldGroupMaps =>
|
||||
({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
entries.map((entry) => [
|
||||
entry.universalIdentifier,
|
||||
{ universalIdentifier: entry.universalIdentifier, id: entry.id },
|
||||
]),
|
||||
),
|
||||
universalIdentifierById: Object.fromEntries(
|
||||
entries.map((entry) => [entry.id, entry.universalIdentifier]),
|
||||
),
|
||||
universalIdentifiersByApplicationId: {},
|
||||
}) as unknown as FlatViewFieldGroupMaps;
|
||||
|
||||
const buildFlatViewFieldMaps = (
|
||||
entries: {
|
||||
universalIdentifier: string;
|
||||
viewId: string;
|
||||
viewFieldGroupId: string | null;
|
||||
position: number;
|
||||
deletedAt: string | null;
|
||||
}[] = [],
|
||||
): FlatViewFieldMaps =>
|
||||
({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
entries.map((entry) => [entry.universalIdentifier, entry]),
|
||||
),
|
||||
universalIdentifierById: {},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
}) as unknown as FlatViewFieldMaps;
|
||||
|
||||
const buildFieldsWidget = ({
|
||||
widgetUniversalIdentifier = 'widget-uid-1',
|
||||
objectMetadataUniversalIdentifier = OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
viewId = VIEW_ID,
|
||||
isVisible = true,
|
||||
viewFieldGroupId = null as string | null,
|
||||
deletedAt = null as string | null,
|
||||
}: {
|
||||
widgetUniversalIdentifier?: string;
|
||||
objectMetadataUniversalIdentifier?: string;
|
||||
viewId?: string | null;
|
||||
isVisible?: boolean;
|
||||
viewFieldGroupId?: string | null;
|
||||
deletedAt?: string | null;
|
||||
} = {}) => ({
|
||||
universalIdentifier: widgetUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
type: WidgetType.FIELDS,
|
||||
deletedAt,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.FIELDS,
|
||||
viewId,
|
||||
newFieldDefaultConfiguration: {
|
||||
isVisible,
|
||||
viewFieldGroupId,
|
||||
},
|
||||
},
|
||||
universalConfiguration: null,
|
||||
});
|
||||
|
||||
const buildFlatPageLayoutWidgetMaps = (
|
||||
widgets: ReturnType<typeof buildFieldsWidget>[],
|
||||
): FlatPageLayoutWidgetMaps =>
|
||||
({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
widgets.map((widget) => [widget.universalIdentifier, widget]),
|
||||
),
|
||||
universalIdentifierById: {},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
}) as unknown as FlatPageLayoutWidgetMaps;
|
||||
|
||||
describe('computeFlatViewFieldsFromFieldsWidgets', () => {
|
||||
describe('when no matching widgets exist', () => {
|
||||
it('should return empty array when widget maps are empty', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps:
|
||||
buildEmptyFlatEntityMaps() as unknown as FlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps(),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array when fieldsToCreate is empty', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should skip widgets for a different object', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier: 'other-obj-uid',
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should skip deleted widgets', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ deletedAt: '2024-01-01T00:00:00.000Z' }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should skip widgets without viewId', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewId: null }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps(),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should skip widgets whose viewId cannot be resolved', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewId: 'non-existent-view-id' }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps(),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating view fields for a single field', () => {
|
||||
it('should create a view field with correct properties', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ isVisible: true }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
viewUniversalIdentifier: VIEW_UNIVERSAL_IDENTIFIER,
|
||||
viewFieldGroupUniversalIdentifier: null,
|
||||
isVisible: true,
|
||||
size: DEFAULT_VIEW_FIELD_SIZE,
|
||||
position: 0,
|
||||
aggregateOperation: null,
|
||||
deletedAt: null,
|
||||
});
|
||||
expect(result[0].universalIdentifier).toBeDefined();
|
||||
expect(result[0].createdAt).toBeDefined();
|
||||
expect(result[0].updatedAt).toBeDefined();
|
||||
});
|
||||
|
||||
it('should respect isVisible: false from configuration', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ isVisible: false }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].isVisible).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('position computation', () => {
|
||||
it('should start at position 0 when no existing view fields', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(0);
|
||||
});
|
||||
|
||||
it('should append after the last existing view field position', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'existing-vf-1',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 3,
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'existing-vf-2',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 7,
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(8);
|
||||
});
|
||||
|
||||
it('should assign sequential positions for multiple fields in the same batch', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-2',
|
||||
},
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-3',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'existing-vf-1',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 2,
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[0].position).toBe(3);
|
||||
expect(result[1].position).toBe(4);
|
||||
expect(result[2].position).toBe(5);
|
||||
});
|
||||
|
||||
it('should ignore deleted view fields when computing position', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'existing-vf-1',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 5,
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'deleted-vf',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 99,
|
||||
deletedAt: '2024-01-01T00:00:00.000Z',
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(6);
|
||||
});
|
||||
|
||||
it('should ignore view fields from a different view', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'other-view-vf',
|
||||
viewId: 'other-view-db-id',
|
||||
viewFieldGroupId: null,
|
||||
position: 50,
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('view field group handling', () => {
|
||||
it('should resolve viewFieldGroupUniversalIdentifier when viewFieldGroupId is set', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewFieldGroupId: VIEW_FIELD_GROUP_ID }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps([
|
||||
{
|
||||
id: VIEW_FIELD_GROUP_ID,
|
||||
universalIdentifier: VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].viewFieldGroupUniversalIdentifier).toBe(
|
||||
VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIER,
|
||||
);
|
||||
});
|
||||
|
||||
it('should set viewFieldGroupUniversalIdentifier to null when viewFieldGroupId is null', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewFieldGroupId: null }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].viewFieldGroupUniversalIdentifier).toBeNull();
|
||||
});
|
||||
|
||||
it('should compute position only from view fields in the same group', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewFieldGroupId: VIEW_FIELD_GROUP_ID }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'vf-in-group',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: VIEW_FIELD_GROUP_ID,
|
||||
position: 2,
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'vf-no-group',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 99,
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'vf-other-group',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: 'other-group-id',
|
||||
position: 50,
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps([
|
||||
{
|
||||
id: VIEW_FIELD_GROUP_ID,
|
||||
universalIdentifier: VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(3);
|
||||
});
|
||||
|
||||
it('should compute position only from ungrouped view fields when viewFieldGroupId is null', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewFieldGroupId: null }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps([
|
||||
{
|
||||
universalIdentifier: 'vf-no-group',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: null,
|
||||
position: 1,
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'vf-in-group',
|
||||
viewId: VIEW_ID,
|
||||
viewFieldGroupId: VIEW_FIELD_GROUP_ID,
|
||||
position: 99,
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result[0].position).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple widgets for the same object', () => {
|
||||
it('should create view fields for each matching widget', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({
|
||||
widgetUniversalIdentifier: 'widget-uid-1',
|
||||
viewId: 'view-db-id-A',
|
||||
}),
|
||||
buildFieldsWidget({
|
||||
widgetUniversalIdentifier: 'widget-uid-2',
|
||||
viewId: 'view-db-id-B',
|
||||
}),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: 'view-db-id-A', universalIdentifier: 'view-uid-A' },
|
||||
{ id: 'view-db-id-B', universalIdentifier: 'view-uid-B' },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].viewUniversalIdentifier).toBe('view-uid-A');
|
||||
expect(result[1].viewUniversalIdentifier).toBe('view-uid-B');
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple objects', () => {
|
||||
it('should create view fields for fields across different objects', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier: 'obj-uid-1',
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
{
|
||||
objectMetadataUniversalIdentifier: 'obj-uid-2',
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-2',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({
|
||||
widgetUniversalIdentifier: 'widget-uid-1',
|
||||
objectMetadataUniversalIdentifier: 'obj-uid-1',
|
||||
viewId: 'view-db-id-A',
|
||||
}),
|
||||
buildFieldsWidget({
|
||||
widgetUniversalIdentifier: 'widget-uid-2',
|
||||
objectMetadataUniversalIdentifier: 'obj-uid-2',
|
||||
viewId: 'view-db-id-B',
|
||||
}),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: 'view-db-id-A', universalIdentifier: 'view-uid-A' },
|
||||
{ id: 'view-db-id-B', universalIdentifier: 'view-uid-B' },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
|
||||
const viewFieldForObj1 = result.find(
|
||||
(viewField) =>
|
||||
viewField.fieldMetadataUniversalIdentifier === 'field-uid-1',
|
||||
);
|
||||
const viewFieldForObj2 = result.find(
|
||||
(viewField) =>
|
||||
viewField.fieldMetadataUniversalIdentifier === 'field-uid-2',
|
||||
);
|
||||
|
||||
expect(viewFieldForObj1?.viewUniversalIdentifier).toBe('view-uid-A');
|
||||
expect(viewFieldForObj2?.viewUniversalIdentifier).toBe('view-uid-B');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unique universal identifiers', () => {
|
||||
it('should generate unique universalIdentifier for each created view field', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-2',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{ id: VIEW_ID, universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER },
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
const universalIdentifiers = result.map(
|
||||
(viewField) => viewField.universalIdentifier,
|
||||
);
|
||||
|
||||
expect(new Set(universalIdentifiers).size).toBe(
|
||||
universalIdentifiers.length,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/metadata-modules/flat-view-field/constants/default-view-field-size.constant';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { type FieldsConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/fields-configuration.dto';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { type AllPageLayoutWidgetConfiguration } from 'src/engine/metadata-modules/page-layout-widget/types/all-page-layout-widget-configuration.type';
|
||||
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
|
||||
|
||||
type FieldToCreateInfo = {
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
fieldMetadataUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
const isFieldsWidgetConfiguration = (
|
||||
configuration: AllPageLayoutWidgetConfiguration,
|
||||
): configuration is FieldsConfigurationDTO => {
|
||||
return (
|
||||
isDefined(configuration) &&
|
||||
configuration.configurationType === WidgetConfigurationType.FIELDS
|
||||
);
|
||||
};
|
||||
|
||||
const getMatchingFieldsWidgets = ({
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatPageLayoutWidgetMaps,
|
||||
}: {
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
}): FlatPageLayoutWidget[] =>
|
||||
Object.values(flatPageLayoutWidgetMaps.byUniversalIdentifier)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
!isDefined(widget.deletedAt) &&
|
||||
widget.type === WidgetType.FIELDS &&
|
||||
widget.objectMetadataUniversalIdentifier ===
|
||||
objectMetadataUniversalIdentifier &&
|
||||
isFieldsWidgetConfiguration(widget.configuration) &&
|
||||
isDefined(widget.configuration.viewId) &&
|
||||
isDefined(widget.configuration.newFieldDefaultConfiguration),
|
||||
);
|
||||
|
||||
const computeNextPosition = ({
|
||||
viewId,
|
||||
viewFieldGroupId,
|
||||
flatViewFieldMaps,
|
||||
}: {
|
||||
viewId: string;
|
||||
viewFieldGroupId: string | null;
|
||||
flatViewFieldMaps: FlatViewFieldMaps;
|
||||
}): number => {
|
||||
const existingViewFields = Object.values(
|
||||
flatViewFieldMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(viewField: FlatViewField) =>
|
||||
!isDefined(viewField.deletedAt) && viewField.viewId === viewId,
|
||||
)
|
||||
.filter(
|
||||
(viewField: FlatViewField) =>
|
||||
viewField.viewFieldGroupId === viewFieldGroupId,
|
||||
);
|
||||
|
||||
if (existingViewFields.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const maxPosition = Math.max(
|
||||
...existingViewFields.map((viewField) => viewField.position),
|
||||
);
|
||||
|
||||
return maxPosition + 1;
|
||||
};
|
||||
|
||||
export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
fieldsToCreate,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
fieldsToCreate: FieldToCreateInfo[];
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
flatViewFieldMaps: FlatViewFieldMaps;
|
||||
flatViewMaps: FlatViewMaps;
|
||||
flatViewFieldGroupMaps: FlatViewFieldGroupMaps;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): UniversalFlatViewField[] => {
|
||||
const flatViewFieldsToCreate: UniversalFlatViewField[] = [];
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const objectMetadataUniversalIdentifiers = [
|
||||
...new Set(
|
||||
fieldsToCreate.map((field) => field.objectMetadataUniversalIdentifier),
|
||||
),
|
||||
];
|
||||
|
||||
const nextPositionByKey = new Map<string, number>();
|
||||
|
||||
for (const objectMetadataUniversalIdentifier of objectMetadataUniversalIdentifiers) {
|
||||
const matchingWidgets = getMatchingFieldsWidgets({
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const fieldsForObject = fieldsToCreate.filter(
|
||||
(field) =>
|
||||
field.objectMetadataUniversalIdentifier ===
|
||||
objectMetadataUniversalIdentifier,
|
||||
);
|
||||
|
||||
for (const widget of matchingWidgets) {
|
||||
if (!isFieldsWidgetConfiguration(widget.configuration)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const configuration = widget.configuration;
|
||||
|
||||
const viewId = configuration.viewId!;
|
||||
const { isVisible, viewFieldGroupId } =
|
||||
configuration.newFieldDefaultConfiguration!;
|
||||
|
||||
const viewUniversalIdentifier =
|
||||
flatViewMaps.universalIdentifierById[viewId] ?? null;
|
||||
|
||||
if (!isDefined(viewUniversalIdentifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const viewFieldGroupUniversalIdentifier = isDefined(viewFieldGroupId)
|
||||
? (flatViewFieldGroupMaps.universalIdentifierById[viewFieldGroupId] ??
|
||||
null)
|
||||
: null;
|
||||
|
||||
const positionKey = `${viewId}:${viewFieldGroupId ?? 'null'}`;
|
||||
|
||||
if (!nextPositionByKey.has(positionKey)) {
|
||||
nextPositionByKey.set(
|
||||
positionKey,
|
||||
computeNextPosition({
|
||||
viewId,
|
||||
viewFieldGroupId,
|
||||
flatViewFieldMaps,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
for (const field of fieldsForObject) {
|
||||
const position = nextPositionByKey.get(positionKey)!;
|
||||
|
||||
nextPositionByKey.set(positionKey, position + 1);
|
||||
|
||||
flatViewFieldsToCreate.push({
|
||||
universalIdentifier: v4(),
|
||||
applicationUniversalIdentifier,
|
||||
fieldMetadataUniversalIdentifier:
|
||||
field.fieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
viewFieldGroupUniversalIdentifier,
|
||||
isVisible,
|
||||
size: DEFAULT_VIEW_FIELD_SIZE,
|
||||
position,
|
||||
aggregateOperation: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flatViewFieldsToCreate;
|
||||
};
|
||||
+7
-4
@@ -2,14 +2,14 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
|
||||
import { v4 as uuidv4, v4 } from 'uuid';
|
||||
import {
|
||||
ViewOpenRecordIn,
|
||||
ViewType,
|
||||
ViewVisibility,
|
||||
} from 'twenty-shared/types';
|
||||
import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
|
||||
import { v4 as uuidv4, v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
@@ -443,7 +443,10 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
};
|
||||
|
||||
if (
|
||||
this.twentyConfigService.get('SHOULD_SEED_STANDARD_RECORD_PAGE_LAYOUTS')
|
||||
existingFeatureFlagsMap[
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
|
||||
] ??
|
||||
false
|
||||
) {
|
||||
flatRecordPageFieldsViewToCreate =
|
||||
this.computeFlatRecordPageFieldsViewToCreate({
|
||||
|
||||
+27
-1
@@ -1,10 +1,30 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsIn, IsNotEmpty, IsOptional, IsUUID } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsIn,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsUUID,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { PageLayoutWidgetConfigurationBase } from 'src/engine/metadata-modules/page-layout-widget/types/page-layout-widget-configurationt-base.type';
|
||||
|
||||
@ObjectType('NewFieldDefaultConfiguration')
|
||||
export class NewFieldDefaultConfigurationDTO {
|
||||
@Field(() => Boolean)
|
||||
@IsBoolean()
|
||||
isVisible: boolean;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
viewFieldGroupId: string | null;
|
||||
}
|
||||
|
||||
@ObjectType('FieldsConfiguration')
|
||||
export class FieldsConfigurationDTO
|
||||
implements PageLayoutWidgetConfigurationBase
|
||||
@@ -18,4 +38,10 @@ export class FieldsConfigurationDTO
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
viewId: string | null;
|
||||
|
||||
@Field(() => NewFieldDefaultConfigurationDTO, { nullable: true })
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => NewFieldDefaultConfigurationDTO)
|
||||
newFieldDefaultConfiguration: NewFieldDefaultConfigurationDTO | null;
|
||||
}
|
||||
|
||||
+15
-7
@@ -243,6 +243,7 @@ export class PageLayoutWidgetService {
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
} =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -251,6 +252,7 @@ export class PageLayoutWidgetService {
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
@@ -263,6 +265,7 @@ export class PageLayoutWidgetService {
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
if (isDefined(createInput.configuration)) {
|
||||
@@ -321,13 +324,17 @@ export class PageLayoutWidgetService {
|
||||
const {
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
} =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatObjectMetadataMaps', 'flatFieldMetadataMaps'],
|
||||
},
|
||||
);
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
} = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
const isConfigurationBeingUpdated = Object.prototype.hasOwnProperty.call(
|
||||
updateData,
|
||||
@@ -357,6 +364,7 @@ export class PageLayoutWidgetService {
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const shouldValidateChartFields =
|
||||
|
||||
+6
@@ -52,6 +52,7 @@ export class PageLayoutDuplicationService {
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
} = await this.getPageLayoutFlatEntityMaps(workspaceId);
|
||||
|
||||
const originalFlatLayout = this.findOriginalLayoutOrThrow(
|
||||
@@ -114,6 +115,7 @@ export class PageLayoutDuplicationService {
|
||||
flatPageLayoutTabMaps: optimisticFlatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
@@ -181,6 +183,7 @@ export class PageLayoutDuplicationService {
|
||||
'flatPageLayoutWidgetMaps',
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
@@ -290,6 +293,7 @@ export class PageLayoutDuplicationService {
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
originalTabsWithWidgets: {
|
||||
tab: FlatPageLayoutTab;
|
||||
@@ -301,6 +305,7 @@ export class PageLayoutDuplicationService {
|
||||
flatPageLayoutTabMaps: AllFlatEntityMaps['flatPageLayoutTabMaps'];
|
||||
flatObjectMetadataMaps: AllFlatEntityMaps['flatObjectMetadataMaps'];
|
||||
flatFieldMetadataMaps: AllFlatEntityMaps['flatFieldMetadataMaps'];
|
||||
flatViewFieldGroupMaps: AllFlatEntityMaps['flatViewFieldGroupMaps'];
|
||||
}): FlatPageLayoutWidget[] {
|
||||
return originalTabsWithWidgets.flatMap(({ tab, widgets }) => {
|
||||
const newTabId = originalTabIdToNewTabIdMap.get(tab.id)!;
|
||||
@@ -320,6 +325,7 @@ export class PageLayoutDuplicationService {
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
+22
-2
@@ -116,11 +116,19 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
} =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatObjectMetadataMaps', 'flatFieldMetadataMaps'],
|
||||
flatMapsKeys: [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -144,6 +152,7 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
@@ -355,6 +364,7 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomApplicationId,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
tabs: UpdatePageLayoutTabWithWidgetsInput[];
|
||||
workspaceId: string;
|
||||
@@ -364,6 +374,7 @@ export class PageLayoutUpdateService {
|
||||
AllFlatEntityMaps,
|
||||
| 'flatObjectMetadataMaps'
|
||||
| 'flatFieldMetadataMaps'
|
||||
| 'flatViewFieldGroupMaps'
|
||||
| 'flatPageLayoutTabMaps'
|
||||
| 'flatPageLayoutWidgetMaps'
|
||||
>): {
|
||||
@@ -386,6 +397,7 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomApplicationId,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
allWidgetsToCreate.push(...widgetsToCreate);
|
||||
@@ -409,6 +421,7 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomApplicationId,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
tabId: string;
|
||||
widgets: UpdatePageLayoutWidgetWithIdInput[];
|
||||
@@ -419,6 +432,7 @@ export class PageLayoutUpdateService {
|
||||
AllFlatEntityMaps,
|
||||
| 'flatObjectMetadataMaps'
|
||||
| 'flatFieldMetadataMaps'
|
||||
| 'flatViewFieldGroupMaps'
|
||||
| 'flatPageLayoutTabMaps'
|
||||
| 'flatPageLayoutWidgetMaps'
|
||||
>): {
|
||||
@@ -487,6 +501,8 @@ export class PageLayoutUpdateService {
|
||||
configuration: widgetInput.configuration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
shouldThrowOnMissingIdentifier: true,
|
||||
}),
|
||||
};
|
||||
@@ -532,6 +548,8 @@ export class PageLayoutUpdateService {
|
||||
configuration: updatedConfiguration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
@@ -578,6 +596,8 @@ export class PageLayoutUpdateService {
|
||||
configuration: restoredConfiguration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
+5
@@ -101,6 +101,11 @@ export const seedFeatureFlags = async ({
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
};
|
||||
|
||||
+39
-2
@@ -128,34 +128,71 @@ const buildFieldsWidgetConfiguration = ({
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.FIELDS,
|
||||
viewId: null,
|
||||
newFieldDefaultConfiguration: {
|
||||
isVisible: true,
|
||||
viewFieldGroupId: null,
|
||||
},
|
||||
},
|
||||
universalConfiguration: {
|
||||
configurationType: WidgetConfigurationType.FIELDS,
|
||||
viewId: null,
|
||||
newFieldDefaultConfiguration: {
|
||||
isVisible: true,
|
||||
viewFieldGroupId: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const views = standardObjectMetadataRelatedEntityIds[objectName]
|
||||
.views as Record<string, { id: string }>;
|
||||
.views as Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
viewFieldGroups?: Record<string, { id: string }>;
|
||||
}
|
||||
>;
|
||||
|
||||
const viewId = views[recordPageFieldsViewName]?.id ?? null;
|
||||
|
||||
// @ts-expect-error ignore
|
||||
const viewDefinition = STANDARD_OBJECTS[objectName].views?.[
|
||||
recordPageFieldsViewName
|
||||
] as { universalIdentifier: string } | undefined;
|
||||
] as
|
||||
| {
|
||||
universalIdentifier: string;
|
||||
viewFieldGroups?: Record<string, { universalIdentifier: string }>;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
const viewUniversalIdentifier = viewDefinition?.universalIdentifier ?? null;
|
||||
|
||||
const otherViewFieldGroupId =
|
||||
views[recordPageFieldsViewName]?.viewFieldGroups?.other?.id ?? null;
|
||||
|
||||
const otherViewFieldGroupUniversalIdentifier =
|
||||
viewDefinition?.viewFieldGroups?.other?.universalIdentifier ?? null;
|
||||
|
||||
const newFieldDefaultConfiguration = {
|
||||
isVisible: true,
|
||||
viewFieldGroupId: otherViewFieldGroupId,
|
||||
};
|
||||
|
||||
const universalNewFieldDefaultConfiguration = {
|
||||
isVisible: true,
|
||||
viewFieldGroupId: otherViewFieldGroupUniversalIdentifier,
|
||||
};
|
||||
|
||||
return {
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.FIELDS,
|
||||
viewId,
|
||||
newFieldDefaultConfiguration,
|
||||
},
|
||||
universalConfiguration: {
|
||||
configurationType: WidgetConfigurationType.FIELDS,
|
||||
viewId: viewUniversalIdentifier,
|
||||
newFieldDefaultConfiguration: universalNewFieldDefaultConfiguration,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ export class CreatePageLayoutWidgetActionHandlerService extends WorkspaceMigrati
|
||||
universalConfiguration: action.flatEntity.universalConfiguration,
|
||||
flatFieldMetadataMaps: allFlatEntityMaps.flatFieldMetadataMaps,
|
||||
flatViewMaps: allFlatEntityMaps.flatViewMaps,
|
||||
flatViewFieldGroupMaps: allFlatEntityMaps.flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const emptyUniversalForeignKeyAggregators =
|
||||
|
||||
+2
@@ -51,6 +51,8 @@ export class UpdatePageLayoutWidgetActionHandlerService extends WorkspaceMigrati
|
||||
universalConfiguration,
|
||||
flatFieldMetadataMaps: allFlatEntityMaps.flatFieldMetadataMaps,
|
||||
flatViewMaps: allFlatEntityMaps.flatViewMaps,
|
||||
flatViewFieldGroupMaps:
|
||||
allFlatEntityMaps.flatViewFieldGroupMaps,
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
+51
-14
@@ -42,10 +42,12 @@ export const fromUniversalConfigurationToFlatPageLayoutWidgetConfiguration = ({
|
||||
universalConfiguration,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
universalConfiguration: FlatPageLayoutWidget['universalConfiguration'];
|
||||
flatFieldMetadataMaps: MetadataFlatEntityMaps<'fieldMetadata'>;
|
||||
flatViewMaps: MetadataFlatEntityMaps<'view'>;
|
||||
flatViewFieldGroupMaps: MetadataFlatEntityMaps<'viewFieldGroup'>;
|
||||
}): FlatPageLayoutWidget['configuration'] => {
|
||||
switch (universalConfiguration.configurationType) {
|
||||
case WidgetConfigurationType.AGGREGATE_CHART: {
|
||||
@@ -198,26 +200,61 @@ export const fromUniversalConfigurationToFlatPageLayoutWidgetConfiguration = ({
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FIELDS: {
|
||||
const { viewId: viewUniversalIdentifier, ...rest } =
|
||||
universalConfiguration;
|
||||
const {
|
||||
viewId: viewUniversalIdentifier,
|
||||
newFieldDefaultConfiguration: universalNewFieldDefaultConfiguration,
|
||||
...rest
|
||||
} = universalConfiguration;
|
||||
|
||||
if (!isDefined(viewUniversalIdentifier)) {
|
||||
return { ...rest, viewId: null };
|
||||
let viewId: string | null = null;
|
||||
|
||||
if (isDefined(viewUniversalIdentifier)) {
|
||||
const flatView = findFlatEntityByUniversalIdentifier({
|
||||
flatEntityMaps: flatViewMaps,
|
||||
universalIdentifier: viewUniversalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View not found for universal identifier: ${viewUniversalIdentifier}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
viewId = flatView.id;
|
||||
}
|
||||
|
||||
const flatView = findFlatEntityByUniversalIdentifier({
|
||||
flatEntityMaps: flatViewMaps,
|
||||
universalIdentifier: viewUniversalIdentifier,
|
||||
});
|
||||
let newFieldDefaultConfiguration:
|
||||
| { isVisible: boolean; viewFieldGroupId: string | null }
|
||||
| null
|
||||
| undefined = universalNewFieldDefaultConfiguration;
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View not found for universal identifier: ${viewUniversalIdentifier}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
if (
|
||||
isDefined(universalNewFieldDefaultConfiguration) &&
|
||||
isDefined(universalNewFieldDefaultConfiguration.viewFieldGroupId)
|
||||
) {
|
||||
const viewFieldGroupUniversalIdentifier =
|
||||
universalNewFieldDefaultConfiguration.viewFieldGroupId;
|
||||
|
||||
const flatViewFieldGroup = findFlatEntityByUniversalIdentifier({
|
||||
flatEntityMaps: flatViewFieldGroupMaps,
|
||||
universalIdentifier: viewFieldGroupUniversalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(flatViewFieldGroup)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View field group not found for universal identifier: ${viewFieldGroupUniversalIdentifier}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
newFieldDefaultConfiguration = {
|
||||
isVisible: universalNewFieldDefaultConfiguration.isVisible,
|
||||
viewFieldGroupId: flatViewFieldGroup.id,
|
||||
};
|
||||
}
|
||||
|
||||
return { ...rest, viewId: flatView.id };
|
||||
return { ...rest, viewId, newFieldDefaultConfiguration };
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.VIEW:
|
||||
|
||||
Reference in New Issue
Block a user