import { EpicReadModel } from './issue.read-model'; import { UserRefReadModel } from './user-ref.read-model'; /** A ticket named by the dashboard, with the number that put it there. */ export class InsightIssueReadModel { id!: string; key!: string; title!: string; /** Status id of the project's settings. */ status!: string; assignee!: UserRefReadModel | null; /** Days in its current status (aging, stuck) or past/to its due date. */ days!: number; dueDate!: string | null; } /** The sprint under way: time gone against work done. */ export class SprintPulseReadModel { sprintId!: string; name!: string; startDate!: string; endDate!: string; /** Days of the sprint, both ends included. */ totalDays!: number; /** Days left after today (0 on the last day; negative once it is over). */ daysLeft!: number; tickets!: number; doneTickets!: number; points!: number; donePoints!: number; /** Points closed per day so far (null on the first day). */ pacePerDay!: number | null; /** Points per day still needed to finish (null when nothing is left). */ neededPerDay!: number | null; /** At this pace, what is open would not be closed in time. */ behind!: boolean; } /** Tickets to look at now. Lists are the worst first, a few at most. */ export class RiskReadModel { overdue!: InsightIssueReadModel[]; overdueCount!: number; /** Due within the next 7 days. */ dueSoon!: InsightIssueReadModel[]; dueSoonCount!: number; /** Waiting for an open ticket that blocks them (or they depend on). */ blocked!: InsightIssueReadModel[]; blockedCount!: number; /** In progress or in QA for `stuckDays` or more without moving. */ stuck!: InsightIssueReadModel[]; stuckCount!: number; stuckDays!: number; } /** How long the work under way has been where it is. */ export class AgingReadModel { issues!: InsightIssueReadModel[]; /** 85% of the tickets finished lately took at most this (cycle time). */ thresholdDays!: number | null; } /** Time tickets spend in a status of the flow, and how many are there. */ export class StatusTimeReadModel { status!: string; /** Average stay of the tickets that left it in the last 90 days. */ averageDays!: number | null; /** Stays measured. */ samples!: number; open!: number; wipLimit!: number | null; overLimit!: boolean; } /** When a planned release would be finished, at the team's real pace. */ export class ReleaseForecastReadModel { releaseId!: string; name!: string; targetDate!: string | null; /** Tickets in it (cancelled ones aside). */ total!: number; finished!: number; /** Half of the simulated futures finish by then (null: no pace yet). */ likelyDate!: string | null; /** 85% of them do. */ safeDate!: string | null; /** * DONE: nothing left. NO_DATE: no target to compare. UNKNOWN: nothing * finished lately to measure a pace. ON_TRACK: 85% in time. AT_RISK: half * in time. LATE: less than half. */ verdict!: 'DONE' | 'NO_DATE' | 'UNKNOWN' | 'ON_TRACK' | 'AT_RISK' | 'LATE'; } /** What has happened since a moment (the viewer's last visit). */ export class ChangesSinceReadModel { since!: string; created!: InsightIssueReadModel[]; createdCount!: number; finished!: InsightIssueReadModel[]; finishedCount!: number; /** Sent back from QA. */ returned!: InsightIssueReadModel[]; returnedCount!: number; /** Times the viewer was mentioned in this project. */ mentions!: number; } /** One person's open work against what they usually close. */ export class TeamLoadReadModel { user!: UserRefReadModel; openTickets!: number; openPoints!: number; /** Their open tickets waiting for another open one. */ blocked!: number; /** Points they closed per sprint, over the last three closed sprints. */ pointsPerSprint!: number | null; /** More open points than they usually close in a sprint. */ overloaded!: boolean; } /** Open tickets missing what planning needs. */ export class BacklogHealthReadModel { open!: number; unestimated!: number; noArea!: number; unassigned!: number; /** Not updated in `staleDays` days. */ stale!: number; staleDays!: number; } /** Bugs created and closed in one week (Monday, UTC). */ export class BugWeekReadModel { week!: string; created!: number; closed!: number; } /** What QA sent back, and let through, per area (last 90 days). */ export class QaByAreaReadModel { /** Area id; null: tickets with no area. */ area!: string | null; returned!: number; passed!: number; } /** Bugs reported in the 14 days after a release shipped. */ export class EscapedBugsReadModel { releaseId!: string; name!: string; releasedAt!: string; bugs!: number; } /** Bugs (types drawn with the bug icon) and QA. */ export class QualityReadModel { /** Open bugs per priority (all five, most urgent first). */ openBugsByPriority!: { priority: string; count: number }[]; /** The last 8 weeks, oldest first. */ bugWeeks!: BugWeekReadModel[]; qaByArea!: QaByAreaReadModel[]; /** The last three shipped releases, newest first. */ escaped!: EscapedBugsReadModel[]; } /** Open tickets per option of a list custom field. */ export class FieldBreakdownReadModel { fieldId!: string; counts!: { value: string; count: number }[]; /** Open tickets with no value in it. */ none!: number; } /** What the project dashboard reads beyond the counts. */ export class ProjectInsightsReadModel { generatedAt!: string; sprint!: SprintPulseReadModel | null; risks!: RiskReadModel; aging!: AgingReadModel; /** In-progress and QA statuses, in board order. */ bottlenecks!: StatusTimeReadModel[]; /** Planned releases, by target date. */ releases!: ReleaseForecastReadModel[]; /** Null unless asked with a `since`. */ changes!: ChangesSinceReadModel | null; /** Members (and others with open tickets), busiest first. */ team!: TeamLoadReadModel[]; backlog!: BacklogHealthReadModel; quality!: QualityReadModel; /** One per active list (SELECT) custom field. */ fields!: FieldBreakdownReadModel[]; } /** One of my projects at a glance, for the portfolio. */ export class PortfolioProjectReadModel { projectId!: string; key!: string; name!: string; isPublic!: boolean; total!: number; open!: number; overdue!: number; blocked!: number; stuck!: number; /** The sprint under way, if any. */ sprint!: SprintPulseReadModel | null; /** Planned releases with their forecast. */ releases!: ReleaseForecastReadModel[]; /** Open epics (nearest due date first), at most six. */ epics!: EpicReadModel[]; updatedAt!: string; }