mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 13:37:22 +00:00
feat(sdk): support viewSorts in app manifests (#19881)
Some checks are pending
CD deploy main / deploy-main (push) Waiting to run
CI Create App E2E minimal / changed-files-check (push) Waiting to run
CI Create App E2E minimal / create-app-e2e-minimal (push) Blocked by required conditions
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Blocked by required conditions
CI Create App / changed-files-check (push) Waiting to run
CI Create App / create-app-test (lint) (push) Blocked by required conditions
CI Create App / create-app-test (test) (push) Blocked by required conditions
CI Create App / create-app-test (typecheck) (push) Blocked by required conditions
CI Create App / ci-create-app-status-check (push) Blocked by required conditions
CI Docs / changed-files-check (push) Waiting to run
CI Docs / docs-lint (push) Blocked by required conditions
CI Emails / changed-files-check (push) Waiting to run
CI Emails / emails-test (push) Blocked by required conditions
CI Emails / ci-emails-status-check (push) Blocked by required conditions
CI Example App Hello World / changed-files-check (push) Waiting to run
CI Example App Hello World / example-app-hello-world (push) Blocked by required conditions
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Blocked by required conditions
CI Example App Postcard / changed-files-check (push) Waiting to run
CI Example App Postcard / example-app-postcard (push) Blocked by required conditions
CI Example App Postcard / ci-example-app-postcard-status-check (push) Blocked by required conditions
Push docs to Crowdin / Push documentation to Crowdin (push) Waiting to run
Push translations to Crowdin / Extract and upload translations (push) Waiting to run
Some checks are pending
CD deploy main / deploy-main (push) Waiting to run
CI Create App E2E minimal / changed-files-check (push) Waiting to run
CI Create App E2E minimal / create-app-e2e-minimal (push) Blocked by required conditions
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Blocked by required conditions
CI Create App / changed-files-check (push) Waiting to run
CI Create App / create-app-test (lint) (push) Blocked by required conditions
CI Create App / create-app-test (test) (push) Blocked by required conditions
CI Create App / create-app-test (typecheck) (push) Blocked by required conditions
CI Create App / ci-create-app-status-check (push) Blocked by required conditions
CI Docs / changed-files-check (push) Waiting to run
CI Docs / docs-lint (push) Blocked by required conditions
CI Emails / changed-files-check (push) Waiting to run
CI Emails / emails-test (push) Blocked by required conditions
CI Emails / ci-emails-status-check (push) Blocked by required conditions
CI Example App Hello World / changed-files-check (push) Waiting to run
CI Example App Hello World / example-app-hello-world (push) Blocked by required conditions
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Blocked by required conditions
CI Example App Postcard / changed-files-check (push) Waiting to run
CI Example App Postcard / example-app-postcard (push) Blocked by required conditions
CI Example App Postcard / ci-example-app-postcard-status-check (push) Blocked by required conditions
Push docs to Crowdin / Push documentation to Crowdin (push) Waiting to run
Push translations to Crowdin / Extract and upload translations (push) Waiting to run
## Summary
Today the SDK lets apps declare `filters` on a view but not `sorts`, so
any view installed via an app manifest can never have a default
ordering. This PR adds declarative view sorts end-to-end: SDK manifest
type, `defineView` validation, CLI scaffold, and the application
install/sync pipeline that converts the manifest into the universal flat
entity used by workspace migrations. The persistence layer
(`ViewSortEntity`, resolvers, action handlers, builders…) already
existed server-side; the missing piece was the manifest → universal-flat
converter and the relation wiring on `view`.
## Changes
**`twenty-shared`**
- Add `ViewSortDirection` enum (`ASC` | `DESC`) and re-export it from
`twenty-shared/types`.
- Add `ViewSortManifest` type and an optional `sorts?:
ViewSortManifest[]` on `ViewManifest`, exported from
`twenty-shared/application`.
**`twenty-sdk`**
- Validate `sorts` entries in `defineView` (`universalIdentifier`,
`fieldMetadataUniversalIdentifier`, `direction` ∈ `ASC`/`DESC`).
- Add a commented `// sorts: [ ... ]` example to the CLI view scaffold
template + matching snapshot assertion.
**`twenty-server`**
- Re-export `ViewSortDirection` from `twenty-shared/types` in
`view-sort/enums/view-sort-direction.ts` (single source of truth,
backward compatible for existing imports).
- New converter `fromViewSortManifestToUniversalFlatViewSort` (+ unit
tests for `ASC` and `DESC`).
- Wire the converter into
`computeApplicationManifestAllUniversalFlatEntityMaps` so
`viewManifest.sorts` are added to `flatViewSortMaps`, mirroring how
filters are processed.
- Replace the `// @ts-expect-error TODO migrate viewSort to v2 /
viewSorts: null` placeholder in `ALL_ONE_TO_MANY_METADATA_RELATIONS`
with the proper relation (`viewSortIds` /
`viewSortUniversalIdentifiers`).
- Update affected snapshots (`get-metadata-related-metadata-names`,
`all-universal-flat-entity-foreign-key-aggregator-properties`).
## Example usage
\`\`\`ts
defineView({
name: 'All issues',
objectUniversalIdentifier: 'issue',
sorts: [
{
universalIdentifier: 'all-issues__sort-created-at',
fieldMetadataUniversalIdentifier: 'createdAt',
direction: 'DESC',
},
],
});
\`\`\`
This commit is contained in:
parent
5c2a0cf115
commit
10c49a49c4
32 changed files with 163 additions and 23 deletions
|
|
@ -27,13 +27,14 @@ describe('getViewBaseFile', () => {
|
|||
expect(result).toContain("objectUniversalIdentifier: 'fill-later'");
|
||||
});
|
||||
|
||||
it('should include commented fields and filters when no fields provided', () => {
|
||||
it('should include commented fields, filters and sorts when no fields provided', () => {
|
||||
const result = getViewBaseFile({
|
||||
name: 'empty-view',
|
||||
});
|
||||
|
||||
expect(result).toContain('// fields: [');
|
||||
expect(result).toContain('// filters: [');
|
||||
expect(result).toContain('// sorts: [');
|
||||
});
|
||||
|
||||
it('should render fields block when fields are provided', () => {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,13 @@ ${fieldsBlock}
|
|||
// value: '',
|
||||
// },
|
||||
// ],
|
||||
// sorts: [
|
||||
// {
|
||||
// universalIdentifier: '...',
|
||||
// fieldMetadataUniversalIdentifier: '...',
|
||||
// direction: 'DESC',
|
||||
// },
|
||||
// ],
|
||||
});
|
||||
`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -79,6 +79,15 @@ export { defineSkill } from '@/sdk/define/skills/define-skill';
|
|||
export { defineView } from '@/sdk/define/views/define-view';
|
||||
export type { ViewConfig } from '@/sdk/define/views/view-config';
|
||||
export { ViewKey } from '@/sdk/define/views/view-key';
|
||||
export type {
|
||||
ViewFieldGroupManifest,
|
||||
ViewFieldManifest,
|
||||
ViewFilterGroupManifest,
|
||||
ViewFilterManifest,
|
||||
ViewGroupManifest,
|
||||
ViewManifestFilterValue,
|
||||
ViewSortManifest,
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
export { getPublicAssetUrl } from '@/sdk/define/get-public-asset-url';
|
||||
|
||||
|
|
@ -94,6 +103,7 @@ export {
|
|||
ViewFilterGroupLogicalOperator,
|
||||
ViewFilterOperand,
|
||||
ViewOpenRecordIn,
|
||||
ViewSortDirection,
|
||||
ViewType,
|
||||
ViewVisibility,
|
||||
} from 'twenty-shared/types';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
import { type DefineEntity } from '@/sdk/define/common/types/define-entity.type';
|
||||
import { createValidationResult } from '@/sdk/define/common/utils/create-validation-result';
|
||||
import { type ViewConfig } from '@/sdk/define/views/view-config';
|
||||
|
|
@ -63,5 +65,24 @@ export const defineView: DefineEntity<ViewConfig> = (config) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (config.sorts) {
|
||||
for (const sort of config.sorts) {
|
||||
if (!sort.universalIdentifier) {
|
||||
errors.push('ViewSort must have a universalIdentifier');
|
||||
}
|
||||
if (!sort.fieldMetadataUniversalIdentifier) {
|
||||
errors.push('ViewSort must have a fieldMetadataUniversalIdentifier');
|
||||
}
|
||||
if (
|
||||
sort.direction !== ViewSortDirection.ASC &&
|
||||
sort.direction !== ViewSortDirection.DESC
|
||||
) {
|
||||
errors.push(
|
||||
`ViewSort direction must be '${ViewSortDirection.ASC}' or '${ViewSortDirection.DESC}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createValidationResult({ config, errors });
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
import { fromViewSortManifestToUniversalFlatViewSort } from 'src/engine/core-modules/application/application-manifest/converters/from-view-sort-manifest-to-universal-flat-view-sort.util';
|
||||
|
||||
describe('fromViewSortManifestToUniversalFlatViewSort', () => {
|
||||
const now = '2026-01-01T00:00:00.000Z';
|
||||
const applicationUniversalIdentifier = 'app-uuid-1';
|
||||
const viewUniversalIdentifier = 'view-uuid-1';
|
||||
|
||||
it('should convert a view sort manifest with ASC direction', () => {
|
||||
const result = fromViewSortManifestToUniversalFlatViewSort({
|
||||
viewSortManifest: {
|
||||
universalIdentifier: 'vsort-uuid-1',
|
||||
fieldMetadataUniversalIdentifier: 'field-uuid-1',
|
||||
direction: ViewSortDirection.ASC,
|
||||
},
|
||||
viewUniversalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.universalIdentifier).toBe('vsort-uuid-1');
|
||||
expect(result.fieldMetadataUniversalIdentifier).toBe('field-uuid-1');
|
||||
expect(result.viewUniversalIdentifier).toBe(viewUniversalIdentifier);
|
||||
expect(result.applicationUniversalIdentifier).toBe(
|
||||
applicationUniversalIdentifier,
|
||||
);
|
||||
expect(result.direction).toBe(ViewSortDirection.ASC);
|
||||
expect(result.createdAt).toBe(now);
|
||||
expect(result.updatedAt).toBe(now);
|
||||
expect(result.deletedAt).toBeNull();
|
||||
});
|
||||
|
||||
it('should convert a view sort manifest with DESC direction', () => {
|
||||
const result = fromViewSortManifestToUniversalFlatViewSort({
|
||||
viewSortManifest: {
|
||||
universalIdentifier: 'vsort-uuid-2',
|
||||
fieldMetadataUniversalIdentifier: 'field-uuid-2',
|
||||
direction: ViewSortDirection.DESC,
|
||||
},
|
||||
viewUniversalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.direction).toBe(ViewSortDirection.DESC);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { type ViewSortManifest } from 'twenty-shared/application';
|
||||
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
|
||||
export const fromViewSortManifestToUniversalFlatViewSort = ({
|
||||
viewSortManifest,
|
||||
viewUniversalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
}: {
|
||||
viewSortManifest: ViewSortManifest;
|
||||
viewUniversalIdentifier: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
now: string;
|
||||
}): UniversalFlatViewSort => {
|
||||
return {
|
||||
universalIdentifier: viewSortManifest.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
fieldMetadataUniversalIdentifier:
|
||||
viewSortManifest.fieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
direction: viewSortManifest.direction,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
};
|
||||
};
|
||||
|
|
@ -25,6 +25,7 @@ import { fromViewFilterGroupManifestToUniversalFlatViewFilterGroup } from 'src/e
|
|||
import { fromViewFilterManifestToUniversalFlatViewFilter } from 'src/engine/core-modules/application/application-manifest/converters/from-view-filter-manifest-to-universal-flat-view-filter.util';
|
||||
import { fromViewGroupManifestToUniversalFlatViewGroup } from 'src/engine/core-modules/application/application-manifest/converters/from-view-group-manifest-to-universal-flat-view-group.util';
|
||||
import { fromViewManifestToUniversalFlatView } from 'src/engine/core-modules/application/application-manifest/converters/from-view-manifest-to-universal-flat-view.util';
|
||||
import { fromViewSortManifestToUniversalFlatViewSort } from 'src/engine/core-modules/application/application-manifest/converters/from-view-sort-manifest-to-universal-flat-view-sort.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { fromAgentManifestToUniversalFlatAgent } from 'src/engine/core-modules/application/utils/from-agent-manifest-to-universal-flat-agent.util';
|
||||
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
|
||||
|
|
@ -325,6 +326,19 @@ export const computeApplicationManifestAllUniversalFlatEntityMaps = ({
|
|||
allUniversalFlatEntityMaps.flatViewGroupMaps,
|
||||
});
|
||||
}
|
||||
|
||||
for (const viewSortManifest of viewManifest.sorts ?? []) {
|
||||
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
|
||||
universalFlatEntity: fromViewSortManifestToUniversalFlatViewSort({
|
||||
viewSortManifest,
|
||||
viewUniversalIdentifier: viewManifest.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
}),
|
||||
universalFlatEntityMapsToMutate:
|
||||
allUniversalFlatEntityMaps.flatViewSortMaps,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const navigationMenuItemManifest of manifest.navigationMenuItems ?? []) {
|
||||
|
|
|
|||
|
|
@ -136,8 +136,11 @@ export const ALL_ONE_TO_MANY_METADATA_RELATIONS = {
|
|||
universalFlatEntityForeignKeyAggregator:
|
||||
'viewFieldGroupUniversalIdentifiers',
|
||||
},
|
||||
// @ts-expect-error TODO migrate viewSort to v2
|
||||
viewSorts: null,
|
||||
viewSorts: {
|
||||
metadataName: 'viewSort',
|
||||
flatEntityForeignKeyAggregator: 'viewSortIds',
|
||||
universalFlatEntityForeignKeyAggregator: 'viewSortUniversalIdentifiers',
|
||||
},
|
||||
},
|
||||
viewField: {},
|
||||
viewFieldGroup: {
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ exports[`getMetadataRelatedMetadataNames should return related metadata names fo
|
|||
"viewFilterGroup",
|
||||
"viewGroup",
|
||||
"viewFieldGroup",
|
||||
"viewSort",
|
||||
]
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'tw
|
|||
import { v4 } from 'uuid';
|
||||
|
||||
import { type CreateViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/create-view-sort.input';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import {
|
|||
} from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
|
||||
import { ViewSortRestApiExceptionFilter } from 'src/engine/metadata-modules/view-sort/filters/view-sort-rest-api-exception.filter';
|
||||
import { ViewSortService } from 'src/engine/metadata-modules/view-sort/services/view-sort.service';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
@Controller('rest/metadata/viewSorts')
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Field, HideField, InputType } from '@nestjs/graphql';
|
|||
import { IsEnum, IsOptional, IsUUID } from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
@InputType()
|
||||
export class CreateViewSortInput {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { Type } from 'class-transformer';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
@InputType()
|
||||
class UpdateViewSortInputUpdates {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
|||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
registerEnumType(ViewSortDirection, { name: 'ViewSortDirection' });
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from 'typeorm';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { type ToolSet } from 'ai';
|
|||
import { z } from 'zod';
|
||||
|
||||
import { formatValidationErrors } from 'src/engine/core-modules/tool-provider/utils/format-validation-errors.util';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
import { ViewSortService } from 'src/engine/metadata-modules/view-sort/services/view-sort.service';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import {
|
|||
FieldMetadataType,
|
||||
ViewFilterGroupLogicalOperator,
|
||||
ViewFilterOperand,
|
||||
ViewSortDirection,
|
||||
ViewType,
|
||||
ViewVisibility,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewQueryParamsService } from 'src/engine/metadata-modules/view/services/view-query-params.service';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
RecordFilterGroupLogicalOperator,
|
||||
type RecordGqlOperationFilter,
|
||||
ViewFilterGroupLogicalOperator,
|
||||
ViewSortDirection,
|
||||
ViewType,
|
||||
} from 'twenty-shared/types';
|
||||
import {
|
||||
|
|
@ -19,7 +20,6 @@ import { type ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query
|
|||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { DEFAULT_TIMEZONE } from 'src/engine/metadata-modules/view/constants/default-timezone.constant';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_FOREIGN_KEY_AGGREGATOR_PROPERTIES should matc
|
|||
"viewFilterGroupUniversalIdentifiers",
|
||||
"viewGroupUniversalIdentifiers",
|
||||
"viewFieldGroupUniversalIdentifiers",
|
||||
"viewSortUniversalIdentifiers",
|
||||
],
|
||||
"viewField": [],
|
||||
"viewFieldGroup": [
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { ViewSortExceptionCode } from 'src/engine/metadata-modules/view-sort/exc
|
|||
import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
|
||||
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
|
||||
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
|
||||
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,10 +19,9 @@ import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object
|
|||
import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util';
|
||||
import { destroyOneView } from 'test/integration/metadata/suites/view/utils/destroy-one-view.util';
|
||||
import { assertViewSortStructure } from 'test/integration/utils/view-test.util';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { FieldMetadataType, ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import {
|
||||
generateViewSortExceptionMessage,
|
||||
ViewSortExceptionMessageKey,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import {
|
||||
ViewFilterGroupLogicalOperator,
|
||||
ViewOpenRecordIn,
|
||||
ViewSortDirection,
|
||||
ViewType,
|
||||
ViewVisibility,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { type ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { type ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
|
||||
export const createViewData = (overrides: Partial<ViewEntity> = {}) => ({
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { v4 } from 'uuid';
|
|||
import { ViewType } from 'twenty-shared/types';
|
||||
|
||||
import { type CreateViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/create-view-sort.input';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
type TestSetup = {
|
||||
createdViewId: string;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { destroyOneView } from 'test/integration/metadata/suites/view/utils/dest
|
|||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { FieldMetadataType, ViewType } from 'twenty-shared/types';
|
||||
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
describe('View Sort creation should succeed', () => {
|
||||
let testObjectMetadataId: string;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { destroyOneView } from 'test/integration/metadata/suites/view/utils/dest
|
|||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { FieldMetadataType, ViewType } from 'twenty-shared/types';
|
||||
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
describe('View Sort deletion should succeed', () => {
|
||||
let testObjectMetadataId: string;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { destroyOneView } from 'test/integration/metadata/suites/view/utils/dest
|
|||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { FieldMetadataType, ViewType } from 'twenty-shared/types';
|
||||
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
describe('View Sort deletion should succeed', () => {
|
||||
let testObjectMetadataId: string;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { destroyOneView } from 'test/integration/metadata/suites/view/utils/dest
|
|||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { FieldMetadataType, ViewType } from 'twenty-shared/types';
|
||||
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
describe('View Sort update should succeed', () => {
|
||||
let testObjectMetadataId: string;
|
||||
|
|
|
|||
|
|
@ -15,10 +15,9 @@ import {
|
|||
} from 'test/integration/rest/utils/view-rest-api.util';
|
||||
import { assertViewSortStructure } from 'test/integration/utils/view-test.util';
|
||||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { FieldMetadataType, ViewSortDirection } from 'twenty-shared/types';
|
||||
|
||||
import { type ViewSortDTO } from 'src/engine/metadata-modules/view-sort/dtos/view-sort.dto';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import {
|
||||
generateViewSortExceptionMessage,
|
||||
ViewSortExceptionMessageKey,
|
||||
|
|
|
|||
|
|
@ -62,5 +62,6 @@ export type {
|
|||
ViewFilterGroupManifest,
|
||||
ViewGroupManifest,
|
||||
ViewFieldGroupManifest,
|
||||
ViewSortManifest,
|
||||
ViewManifest,
|
||||
} from './viewManifestType';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
type ViewFilterGroupLogicalOperator,
|
||||
type ViewFilterOperand,
|
||||
type ViewOpenRecordIn,
|
||||
type ViewSortDirection,
|
||||
type ViewType,
|
||||
type ViewVisibility,
|
||||
} from '@/types';
|
||||
|
|
@ -52,6 +53,11 @@ export type ViewFieldGroupManifest = SyncableEntityOptions & {
|
|||
isVisible?: boolean;
|
||||
};
|
||||
|
||||
export type ViewSortManifest = SyncableEntityOptions & {
|
||||
fieldMetadataUniversalIdentifier: string;
|
||||
direction: ViewSortDirection;
|
||||
};
|
||||
|
||||
export type ViewManifest = SyncableEntityOptions & {
|
||||
name: string;
|
||||
objectUniversalIdentifier: string;
|
||||
|
|
@ -67,4 +73,5 @@ export type ViewManifest = SyncableEntityOptions & {
|
|||
filterGroups?: ViewFilterGroupManifest[];
|
||||
groups?: ViewGroupManifest[];
|
||||
fieldGroups?: ViewFieldGroupManifest[];
|
||||
sorts?: ViewSortManifest[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -284,5 +284,6 @@ export { ViewFilterOperand } from './ViewFilterOperand';
|
|||
export { ViewFilterOperandDeprecated } from './ViewFilterOperandDeprecated';
|
||||
export { ViewKey } from './ViewKey';
|
||||
export { ViewOpenRecordIn } from './ViewOpenRecordIn';
|
||||
export { ViewSortDirection } from './ViewSortDirection';
|
||||
export { ViewType } from './ViewType';
|
||||
export { ViewVisibility } from './ViewVisibility';
|
||||
|
|
|
|||
Loading…
Reference in a new issue