import Monitor from "./Monitor"; import MonitorStatus from "./MonitorStatus"; import Project from "./Project"; import User from "./User"; import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel"; import Route from "../../Types/API/Route"; import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl"; import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl"; import CanAccessIfCanReadOn from "../../Types/Database/CanAccessIfCanReadOn"; import ColumnType from "../../Types/Database/ColumnType"; import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint"; import EnableDocumentation from "../../Types/Database/EnableDocumentation"; import EnableWorkflow from "../../Types/Database/EnableWorkflow"; import SlugifyColumn from "../../Types/Database/SlugifyColumn"; import TableColumn from "../../Types/Database/TableColumn"; import TableColumnType from "../../Types/Database/TableColumnType"; import TableMetadata from "../../Types/Database/TableMetadata"; import TenantColumn from "../../Types/Database/TenantColumn"; import IconProp from "../../Types/Icon/IconProp"; import { JSONObject } from "../../Types/JSON"; import ObjectID from "../../Types/ObjectID"; import Permission from "../../Types/Permission"; import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm"; @EnableDocumentation() @CanAccessIfCanReadOn("monitor") @TenantColumn("projectId") @Index(["monitorId", "projectId", "startsAt"]) // Composite index for efficient timeline queries @Index(["monitorId", "startsAt"]) // Alternative index for monitor-specific timeline queries @TableAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], delete: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.DeleteMonitorStatusTimeline, ], update: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.EditMonitorStatusTimeline, ], }) @EnableWorkflow({ create: true, delete: true, update: true, read: true, }) @CrudApiEndpoint(new Route("/monitor-status-timeline")) @SlugifyColumn("name", "slug") @Entity({ name: "MonitorStatusTimeline", }) @Index(["monitorId", "startsAt"]) @TableMetadata({ tableName: "MonitorStatusTimeline", singularName: "Monitor Status Event", pluralName: "Monitor Status Events", icon: IconProp.List, tableDescription: "Change state of the monitor (Operational to Offline for example)", }) export default class MonitorStatusTimeline extends BaseModel { @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ manyToOneRelationColumn: "projectId", type: TableColumnType.Entity, modelType: Project, title: "Project", description: "Relation to Project Resource in which this object belongs", example: "5f8b9c0d-e1a2-4b3c-8d5e-6f7a8b9c0d1e", }) @ManyToOne( () => { return Project; }, { eager: false, nullable: true, onDelete: "CASCADE", orphanedRowAction: "nullify", }, ) @JoinColumn({ name: "projectId" }) public project?: Project = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @Index() @TableColumn({ type: TableColumnType.ObjectID, required: true, canReadOnRelationQuery: true, title: "Project ID", description: "ID of your OneUptime Project in which this object belongs", example: "5f8b9c0d-e1a2-4b3c-8d5e-6f7a8b9c0d1e", }) @Column({ type: ColumnType.ObjectID, nullable: false, transformer: ObjectID.getDatabaseTransformer(), }) public projectId?: ObjectID = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ manyToOneRelationColumn: "monitorId", type: TableColumnType.Entity, modelType: Monitor, title: "Monitor", description: "Relation to Monitor Resource in which this object belongs", example: "a7b8c9d0-e1f2-3456-789a-bcdef0123456", }) @ManyToOne( () => { return Monitor; }, { eager: false, nullable: true, onDelete: "CASCADE", orphanedRowAction: "nullify", }, ) @JoinColumn({ name: "monitorId" }) public monitor?: Monitor = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @Index() @TableColumn({ type: TableColumnType.ObjectID, required: true, title: "Monitor ID", description: "Relation to Monitor ID Resource in which this object belongs", example: "a7b8c9d0-e1f2-3456-789a-bcdef0123456", }) @Column({ type: ColumnType.ObjectID, nullable: false, transformer: ObjectID.getDatabaseTransformer(), }) public monitorId?: ObjectID = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ manyToOneRelationColumn: "createdByUserId", type: TableColumnType.Entity, modelType: User, title: "Created by User", description: "Relation to User who created this object (if this object was created by a User)", example: "b2c3d4e5-f6a7-8901-bcde-f12345678901", }) @ManyToOne( () => { return User; }, { eager: false, nullable: true, onDelete: "SET NULL", orphanedRowAction: "nullify", }, ) @JoinColumn({ name: "createdByUserId" }) public createdByUser?: User = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ type: TableColumnType.ObjectID, title: "Created by User ID", description: "User ID who created this object (if this object was created by a User)", example: "b2c3d4e5-f6a7-8901-bcde-f12345678901", }) @Column({ type: ColumnType.ObjectID, nullable: true, transformer: ObjectID.getDatabaseTransformer(), }) public createdByUserId?: ObjectID = undefined; @ColumnAccessControl({ create: [], read: [], update: [], }) @TableColumn({ manyToOneRelationColumn: "deletedByUserId", type: TableColumnType.Entity, title: "Deleted by User", modelType: User, description: "Relation to User who deleted this object (if this object was deleted by a User)", example: "c3d4e5f6-a7b8-9012-cdef-123456789012", }) @ManyToOne( () => { return User; }, { cascade: false, eager: false, nullable: true, onDelete: "SET NULL", orphanedRowAction: "nullify", }, ) @JoinColumn({ name: "deletedByUserId" }) public deletedByUser?: User = undefined; @ColumnAccessControl({ create: [], read: [], update: [], }) @TableColumn({ type: TableColumnType.ObjectID, title: "Deleted by User ID", description: "User ID who deleted this object (if this object was deleted by a User)", example: "c3d4e5f6-a7b8-9012-cdef-123456789012", }) @Column({ type: ColumnType.ObjectID, nullable: true, transformer: ObjectID.getDatabaseTransformer(), }) public deletedByUserId?: ObjectID = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.EditMonitorStatusTimeline, ], }) @TableColumn({ manyToOneRelationColumn: "monitorStatusId", type: TableColumnType.Entity, modelType: MonitorStatus, title: "Monitor Status", description: "Relation to Monitor Status Resource in which this object belongs", example: "b8c9d0e1-f2a3-4567-890a-bcdef0123456", }) @ManyToOne( () => { return MonitorStatus; }, { eager: false, nullable: true, orphanedRowAction: "nullify", }, ) @JoinColumn({ name: "monitorStatusId" }) public monitorStatus?: MonitorStatus = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.EditMonitorStatusTimeline, ], }) @Index() @TableColumn({ type: TableColumnType.ObjectID, required: true, title: "Monitor Status ID", description: "Relation to Monitor Status ID Resource in which this object belongs", example: "b8c9d0e1-f2a3-4567-890a-bcdef0123456", }) @Column({ type: ColumnType.ObjectID, nullable: false, transformer: ObjectID.getDatabaseTransformer(), }) public monitorStatusId?: ObjectID = undefined; @ColumnAccessControl({ create: [], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @Index() @TableColumn({ type: TableColumnType.Boolean, computed: true, hideColumnInDocumentation: true, required: true, isDefaultValueColumn: true, title: "Are Owners Notified", description: "Are owners notified of status change?", defaultValue: false, example: true, }) @Column({ type: ColumnType.Boolean, nullable: false, default: false, }) public isOwnerNotified?: boolean = undefined; @ColumnAccessControl({ create: [], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ isDefaultValueColumn: false, required: false, type: TableColumnType.JSON, computed: true, example: { previousStatus: "operational", newStatus: "degraded", responseTime: 2500, probeLocation: "us-east-1", }, }) @Column({ type: ColumnType.JSON, nullable: true, unique: false, }) public statusChangeLog?: JSONObject = undefined; @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ type: TableColumnType.Markdown, required: false, isDefaultValueColumn: false, title: "Root Cause", description: "What is the root cause of this status change?", example: "API response time exceeded threshold of 2000ms due to database query optimization needed on user table.", }) @Column({ type: ColumnType.Markdown, nullable: true, }) public rootCause?: string = undefined; @Index() @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ type: TableColumnType.Date, title: "Ends At", description: "When did this status change end?", example: "2024-01-15T16:20:00.000Z", }) @Column({ type: ColumnType.Date, nullable: true, unique: false, }) public endsAt?: Date = undefined; @Index() @ColumnAccessControl({ create: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.CreateMonitorStatusTimeline, ], read: [ Permission.ProjectOwner, Permission.ProjectAdmin, Permission.ProjectMember, Permission.ReadMonitorStatusTimeline, Permission.ReadAllProjectResources, ], update: [], }) @TableColumn({ type: TableColumnType.Date, title: "Starts At", description: "When did this status change?", example: "2024-01-15T15:45:00.000Z", }) @Column({ type: ColumnType.Date, nullable: true, unique: false, }) public startsAt?: Date = undefined; }