feat: dashboard forecasts releases, tells what changed and weighs the load
The insights reading grows (GraphQL insights(since:), REST ?since=, MCP): - planned releases with a likely (p50) and safe (p85) finish date from a Monte Carlo over the last six weeks of finished work, one after another, and a verdict against their target; - with `since` (the viewer's last visit, kept in the browser): tickets created, finished and sent back from QA, and their mentions; - each person's open points against what they closed per sprint lately; - open tickets without estimate, area or assignee, or untouched for 90 days, each count opening the list filtered (new noEstimate, noArea and updatedBefore filters). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,15 @@ type AutomationTriggerSpec {
|
||||
status: String
|
||||
}
|
||||
|
||||
type BacklogHealth {
|
||||
noArea: Int!
|
||||
open: Int!
|
||||
stale: Int!
|
||||
staleDays: Int!
|
||||
unassigned: Int!
|
||||
unestimated: Int!
|
||||
}
|
||||
|
||||
type BoardColumn {
|
||||
issues: [Issue!]!
|
||||
status: String!
|
||||
@@ -184,6 +193,22 @@ input ChangeIssueStatusInput {
|
||||
status: String!
|
||||
}
|
||||
|
||||
"""What happened after a moment"""
|
||||
type ChangesSince {
|
||||
created: [InsightIssue!]!
|
||||
createdCount: Int!
|
||||
finished: [InsightIssue!]!
|
||||
finishedCount: Int!
|
||||
|
||||
"""Times I was mentioned here"""
|
||||
mentions: Int!
|
||||
|
||||
"""Sent back from QA"""
|
||||
returned: [InsightIssue!]!
|
||||
returnedCount: Int!
|
||||
since: String!
|
||||
}
|
||||
|
||||
"""A step inside a ticket that does not deserve a ticket of its own"""
|
||||
type ChecklistItem {
|
||||
done: Boolean!
|
||||
@@ -598,6 +623,12 @@ input IssueFilterInput {
|
||||
dueTo: String
|
||||
labels: [String!]
|
||||
|
||||
"""Only tickets with no area"""
|
||||
noArea: Boolean
|
||||
|
||||
"""Only tickets nobody estimated"""
|
||||
noEstimate: Boolean
|
||||
|
||||
"""Only tickets in no sprint"""
|
||||
noSprint: Boolean
|
||||
|
||||
@@ -615,6 +646,9 @@ input IssueFilterInput {
|
||||
types: [String!]
|
||||
unassigned: Boolean
|
||||
|
||||
"""Only tickets not updated since this instant (ISO)"""
|
||||
updatedBefore: String
|
||||
|
||||
"""Only the tickets I follow (none when anonymous)"""
|
||||
watching: Boolean
|
||||
}
|
||||
@@ -978,7 +1012,10 @@ type Project {
|
||||
"""
|
||||
The dashboard: sprint under way, overdue / blocked / stuck tickets, aging and bottlenecks
|
||||
"""
|
||||
insights: ProjectInsights!
|
||||
insights(
|
||||
"""ISO instant (e.g. my last visit): also tell what changed after it"""
|
||||
since: String
|
||||
): ProjectInsights!
|
||||
|
||||
"""Anyone can read it, also without signing in"""
|
||||
isPublic: Boolean!
|
||||
@@ -1021,13 +1058,21 @@ type ProjectChange {
|
||||
version: Int!
|
||||
}
|
||||
|
||||
"""The dashboard: sprint under way, risks, aging and bottlenecks"""
|
||||
"""
|
||||
The dashboard: sprint under way, risks, aging, bottlenecks, release forecasts, team load, backlog health and changes
|
||||
"""
|
||||
type ProjectInsights {
|
||||
aging: Aging!
|
||||
backlog: BacklogHealth!
|
||||
bottlenecks: [StatusTime!]!
|
||||
|
||||
"""Only when asked with `since`"""
|
||||
changes: ChangesSince
|
||||
generatedAt: String!
|
||||
releases: [ReleaseForecast!]!
|
||||
risks: Risks!
|
||||
sprint: SprintPulse
|
||||
team: [TeamLoad!]!
|
||||
}
|
||||
|
||||
type ProjectMember {
|
||||
@@ -1237,6 +1282,24 @@ type ReleaseChange {
|
||||
version: Int!
|
||||
}
|
||||
|
||||
"""When a planned release would be finished, at the real pace"""
|
||||
type ReleaseForecast {
|
||||
finished: Int!
|
||||
|
||||
"""Half of the simulated futures finish by then"""
|
||||
likelyDate: String
|
||||
name: String!
|
||||
releaseId: ID!
|
||||
|
||||
"""85% finish by then"""
|
||||
safeDate: String
|
||||
targetDate: String
|
||||
total: Int!
|
||||
|
||||
"""DONE, NO_DATE, UNKNOWN (no pace yet), ON_TRACK, AT_RISK or LATE"""
|
||||
verdict: String!
|
||||
}
|
||||
|
||||
type ReleaseProgress {
|
||||
byStatus: [CountByStatus!]!
|
||||
finished: Int!
|
||||
@@ -1450,6 +1513,17 @@ type Subscription {
|
||||
sprintChanged(projectId: ID!): SprintChange!
|
||||
}
|
||||
|
||||
type TeamLoad {
|
||||
blocked: Int!
|
||||
openPoints: Int!
|
||||
openTickets: Int!
|
||||
overloaded: Boolean!
|
||||
|
||||
"""Points closed per sprint, last three closed sprints"""
|
||||
pointsPerSprint: Float
|
||||
user: UserRef!
|
||||
}
|
||||
|
||||
type Throughput {
|
||||
count: Int!
|
||||
user: UserRef
|
||||
|
||||
Reference in New Issue
Block a user