Add calendar view type (#14475)

This commit is contained in:
Weiko
2025-09-14 16:34:10 +02:00
committed by GitHub
parent 6a96c85eed
commit f46d67f9f3
12 changed files with 119 additions and 0 deletions
@@ -529,6 +529,7 @@ export type ConnectionParametersOutput = {
export type CoreView = {
__typename?: 'CoreView';
anyFieldFilterValue?: Maybe<Scalars['String']>;
calendarLayout?: Maybe<ViewCalendarLayout>;
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
icon: Scalars['String'];
@@ -808,6 +809,7 @@ export type CreateViewGroupInput = {
export type CreateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
calendarLayout?: InputMaybe<ViewCalendarLayout>;
icon: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
@@ -1032,6 +1034,7 @@ export type FeatureFlagDto = {
export enum FeatureFlagKey {
IS_AIRTABLE_INTEGRATION_ENABLED = 'IS_AIRTABLE_INTEGRATION_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_CALENDAR_VIEW_ENABLED = 'IS_CALENDAR_VIEW_ENABLED',
IS_CORE_VIEW_ENABLED = 'IS_CORE_VIEW_ENABLED',
IS_CORE_VIEW_SYNCING_ENABLED = 'IS_CORE_VIEW_SYNCING_ENABLED',
IS_DATABASE_EVENT_TRIGGER_ENABLED = 'IS_DATABASE_EVENT_TRIGGER_ENABLED',
@@ -3654,6 +3657,7 @@ export type UpdateViewGroupInput = {
export type UpdateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
calendarLayout?: InputMaybe<ViewCalendarLayout>;
icon?: InputMaybe<Scalars['String']>;
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
@@ -3836,6 +3840,12 @@ export type VersionInfo = {
latestVersion: Scalars['String'];
};
export enum ViewCalendarLayout {
DAY = 'DAY',
MONTH = 'MONTH',
WEEK = 'WEEK'
}
export enum ViewFilterGroupLogicalOperator {
AND = 'AND',
NOT = 'NOT',
@@ -3876,6 +3886,7 @@ export enum ViewSortDirection {
}
export enum ViewType {
CALENDAR = 'CALENDAR',
KANBAN = 'KANBAN',
TABLE = 'TABLE'
}
@@ -529,6 +529,7 @@ export type ConnectionParametersOutput = {
export type CoreView = {
__typename?: 'CoreView';
anyFieldFilterValue?: Maybe<Scalars['String']>;
calendarLayout?: Maybe<ViewCalendarLayout>;
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
icon: Scalars['String'];
@@ -772,6 +773,7 @@ export type CreateViewGroupInput = {
export type CreateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
calendarLayout?: InputMaybe<ViewCalendarLayout>;
icon: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
@@ -996,6 +998,7 @@ export type FeatureFlagDto = {
export enum FeatureFlagKey {
IS_AIRTABLE_INTEGRATION_ENABLED = 'IS_AIRTABLE_INTEGRATION_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_CALENDAR_VIEW_ENABLED = 'IS_CALENDAR_VIEW_ENABLED',
IS_CORE_VIEW_ENABLED = 'IS_CORE_VIEW_ENABLED',
IS_CORE_VIEW_SYNCING_ENABLED = 'IS_CORE_VIEW_SYNCING_ENABLED',
IS_DATABASE_EVENT_TRIGGER_ENABLED = 'IS_DATABASE_EVENT_TRIGGER_ENABLED',
@@ -3492,6 +3495,7 @@ export type UpdateViewGroupInput = {
export type UpdateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
calendarLayout?: InputMaybe<ViewCalendarLayout>;
icon?: InputMaybe<Scalars['String']>;
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
@@ -3664,6 +3668,12 @@ export type VersionInfo = {
latestVersion: Scalars['String'];
};
export enum ViewCalendarLayout {
DAY = 'DAY',
MONTH = 'MONTH',
WEEK = 'WEEK'
}
export enum ViewFilterGroupLogicalOperator {
AND = 'AND',
NOT = 'NOT',
@@ -3704,6 +3714,7 @@ export enum ViewSortDirection {
}
export enum ViewType {
CALENDAR = 'CALENDAR',
KANBAN = 'KANBAN',
TABLE = 'TABLE'
}
@@ -0,0 +1,61 @@
import { type MigrationInterface, type QueryRunner } from 'typeorm';
export class AddCalendarTypeToViewTable1757858496548
implements MigrationInterface
{
name = 'AddCalendarTypeToViewTable1757858496548';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "core"."view_calendarlayout_enum" AS ENUM('DAY', 'WEEK', 'MONTH')`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ADD "calendarLayout" "core"."view_calendarlayout_enum"`,
);
await queryRunner.query(
`ALTER TYPE "core"."view_type_enum" RENAME TO "view_type_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "core"."view_type_enum" AS ENUM('TABLE', 'KANBAN', 'CALENDAR')`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" TYPE "core"."view_type_enum" USING "type"::"text"::"core"."view_type_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" SET DEFAULT 'TABLE'`,
);
await queryRunner.query(`DROP TYPE "core"."view_type_enum_old"`);
await queryRunner.query(
`ALTER TABLE "core"."view" ADD CONSTRAINT "CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR" CHECK (("type" != 'CALENDAR' OR "calendarLayout" IS NOT NULL))`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."view" DROP CONSTRAINT "CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR"`,
);
await queryRunner.query(
`CREATE TYPE "core"."view_type_enum_old" AS ENUM('KANBAN', 'TABLE')`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" TYPE "core"."view_type_enum_old" USING "type"::"text"::"core"."view_type_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" ALTER COLUMN "type" SET DEFAULT 'TABLE'`,
);
await queryRunner.query(`DROP TYPE "core"."view_type_enum"`);
await queryRunner.query(
`ALTER TYPE "core"."view_type_enum_old" RENAME TO "view_type_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."view" DROP COLUMN "calendarLayout"`,
);
await queryRunner.query(`DROP TYPE "core"."view_calendarlayout_enum"`);
}
}
@@ -15,4 +15,5 @@ export enum FeatureFlagKey {
IS_MESSAGE_FOLDER_CONTROL_ENABLED = 'IS_MESSAGE_FOLDER_CONTROL_ENABLED',
IS_WORKFLOW_ITERATOR_ENABLED = 'IS_WORKFLOW_ITERATOR_ENABLED',
IS_DATABASE_EVENT_TRIGGER_ENABLED = 'IS_DATABASE_EVENT_TRIGGER_ENABLED',
IS_CALENDAR_VIEW_ENABLED = 'IS_CALENDAR_VIEW_ENABLED',
}
@@ -2,6 +2,7 @@ import { Field, InputType } from '@nestjs/graphql';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ViewCalendarLayout } from 'src/engine/core-modules/view/enums/view-calendar-layout.enum';
import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
@@ -46,4 +47,7 @@ export class CreateViewInput {
@Field({ nullable: true })
anyFieldFilterValue?: string;
@Field(() => ViewCalendarLayout, { nullable: true })
calendarLayout?: ViewCalendarLayout;
}
@@ -2,6 +2,7 @@ import { Field, InputType } from '@nestjs/graphql';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ViewCalendarLayout } from 'src/engine/core-modules/view/enums/view-calendar-layout.enum';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
@@ -40,4 +41,7 @@ export class UpdateViewInput {
@Field({ nullable: true })
anyFieldFilterValue?: string;
@Field(() => ViewCalendarLayout, { nullable: true })
calendarLayout?: ViewCalendarLayout;
}
@@ -9,6 +9,7 @@ import { ViewFilterGroupDTO } from 'src/engine/core-modules/view/dtos/view-filte
import { ViewFilterDTO } from 'src/engine/core-modules/view/dtos/view-filter.dto';
import { ViewGroupDTO } from 'src/engine/core-modules/view/dtos/view-group.dto';
import { ViewSortDTO } from 'src/engine/core-modules/view/dtos/view-sort.dto';
import { ViewCalendarLayout } from 'src/engine/core-modules/view/enums/view-calendar-layout.enum';
import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
@@ -16,6 +17,7 @@ import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
registerEnumType(ViewOpenRecordIn, { name: 'ViewOpenRecordIn' });
registerEnumType(ViewType, { name: 'ViewType' });
registerEnumType(ViewKey, { name: 'ViewKey' });
registerEnumType(ViewCalendarLayout, { name: 'ViewCalendarLayout' });
@ObjectType('CoreView')
export class ViewDTO {
@@ -64,6 +66,9 @@ export class ViewDTO {
@Field(() => String, { nullable: true })
anyFieldFilterValue?: string | null;
@Field(() => ViewCalendarLayout, { nullable: true })
calendarLayout: ViewCalendarLayout | null;
@Field()
createdAt: Date;
@@ -1,4 +1,5 @@
import {
Check,
Column,
CreateDateColumn,
DeleteDateColumn,
@@ -20,6 +21,7 @@ import { ViewFilterGroupEntity } from 'src/engine/core-modules/view/entities/vie
import { ViewFilterEntity } from 'src/engine/core-modules/view/entities/view-filter.entity';
import { ViewGroupEntity } from 'src/engine/core-modules/view/entities/view-group.entity';
import { ViewSortEntity } from 'src/engine/core-modules/view/entities/view-sort.entity';
import { ViewCalendarLayout } from 'src/engine/core-modules/view/enums/view-calendar-layout.enum';
import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
@@ -31,6 +33,10 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
'workspaceId',
'objectMetadataId',
])
@Check(
'CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR',
`("type" != 'CALENDAR' OR "calendarLayout" IS NOT NULL)`,
)
export class ViewEntity extends SyncableEntity implements Required<ViewEntity> {
@PrimaryGeneratedColumn('uuid')
id: string;
@@ -94,6 +100,14 @@ export class ViewEntity extends SyncableEntity implements Required<ViewEntity> {
@Column({ nullable: true, type: 'uuid' })
kanbanAggregateOperationFieldMetadataId: string | null;
@Column({
type: 'enum',
enum: Object.values(ViewCalendarLayout),
nullable: true,
default: null,
})
calendarLayout: ViewCalendarLayout | null;
@Column({ nullable: false, type: 'uuid' })
workspaceId: string;
@@ -0,0 +1,5 @@
export enum ViewCalendarLayout {
DAY = 'DAY',
WEEK = 'WEEK',
MONTH = 'MONTH',
}
@@ -1,4 +1,5 @@
export enum ViewType {
TABLE = 'TABLE',
KANBAN = 'KANBAN',
CALENDAR = 'CALENDAR',
}
@@ -32,5 +32,6 @@ export const fromPartialFlatViewToFlatViewWithDefault = (
anyFieldFilterValue: partialFlatView.anyFieldFilterValue ?? null,
universalIdentifier: partialFlatView.universalIdentifier ?? viewId,
viewFieldIds: partialFlatView.viewFieldIds ?? [],
calendarLayout: partialFlatView.calendarLayout ?? null,
};
};
@@ -138,6 +138,7 @@ describe('WorkspaceEntityManager', () => {
IS_MESSAGE_FOLDER_CONTROL_ENABLED: false,
IS_WORKFLOW_ITERATOR_ENABLED: false,
IS_DATABASE_EVENT_TRIGGER_ENABLED: false,
IS_CALENDAR_VIEW_ENABLED: false,
},
eventEmitterService: {
emitMutationEvent: jest.fn(),