Files
task-stream/apps/api/schema.gql
Josep Piguillem ea4ef82239 feat: replies to comments
A comment can answer another one (replyTo), one level deep: answering a
reply joins the same thread, and it must be on the same ticket. Whoever
wrote the comment gets a new REPLIED notification, and the activity says
"respondió a un comentario".

A comment deleted while it has replies stays, without its text
(deleted: true), so the thread still reads; it goes with its last reply
and does not count in commentCount.

The ticket page shows threads with their replies indented and a
"Responder" box; REST, GraphQL and the MCP (add_comment, get_issue) take
and show replyTo. Existing comments are unchanged. Docs, Word and PDF
updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:14:37 +02:00

1365 lines
28 KiB
GraphQL

# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------
type Activity {
actor: UserRef!
id: ID!
issueId: ID
issueKey: String
occurredAt: String!
projectId: ID!
summary: String!
type: String!
}
input AddChecklistItemInput {
issueId: ID!
text: String!
}
type AreaOption {
archived: Boolean!
id: String!
name: String!
}
input AreaOptionInput {
archived: Boolean! = false
id: String!
name: String!
}
"""
A file on a ticket. Download it from the REST API: GET /api/issues/{issueId}/attachments/{id}
"""
type Attachment {
"""The comment it was attached to, if any"""
commentId: ID
fileName: String!
id: ID!
mimeType: String!
"""Bytes"""
size: Int!
uploadedAt: String!
uploadedBy: UserRef!
}
"""When this happens to a ticket, if it is like this, do that"""
type Automation {
action: AutomationActionSpec!
active: Boolean!
conditions: AutomationConditions!
createdAt: String!
createdBy: UserRef!
id: ID!
"""Why the last run did nothing"""
lastError: String
lastRunAt: String
name: String!
projectId: ID!
runs: Int!
trigger: AutomationTriggerSpec!
}
"""What a rule does to the ticket"""
enum AutomationAction {
ADD_COMMENT
ADD_LABEL
ADD_TO_ACTIVE_SPRINT
ASSIGN
ASSIGN_REPORTER
SET_PRIORITY
SET_STATUS
}
input AutomationActionInput {
kind: AutomationAction!
value: String
}
type AutomationActionSpec {
kind: AutomationAction!
"""Status, member id, label, priority or comment text"""
value: String
}
type AutomationConditions {
areas: [String!]
label: String
priorities: [IssuePriority!]
types: [String!]
}
input AutomationConditionsInput {
areas: [String!]
label: String
priorities: [IssuePriority!]
types: [String!]
}
"""What starts a rule"""
enum AutomationTrigger {
COMMENT_ADDED
ISSUE_ASSIGNED
ISSUE_CREATED
PULL_REQUEST_MERGED
STATUS_CHANGED
}
input AutomationTriggerInput {
kind: AutomationTrigger!
status: String
}
type AutomationTriggerSpec {
kind: AutomationTrigger!
"""STATUS_CHANGED: only into this status"""
status: String
}
type BoardColumn {
issues: [Issue!]!
status: String!
total: Int!
}
type BulkIssueResult {
error: String
issueId: ID!
ok: Boolean!
}
type BulkResult {
results: [BulkIssueResult!]!
updated: Int!
}
input BulkUpdateIssuesInput {
addLabels: [String!]
assigneeId: ID
issueIds: [ID!]!
"""Out of their release"""
noRelease: Boolean
"""Back to the backlog"""
noSprint: Boolean
priority: IssuePriority
releaseId: ID
sprintId: ID
status: String
"""Unassign everything"""
unassign: Boolean
}
input ChangeIssueStatusInput {
issueId: ID!
"""Required by statuses with requiresReason"""
reason: String
"""A status id"""
status: String!
}
"""A step inside a ticket that does not deserve a ticket of its own"""
type ChecklistItem {
done: Boolean!
id: ID!
text: String!
}
"""How far the tickets hanging from one have got"""
type ChildProgress {
"""Done or cancelled"""
finished: Int!
finishedStoryPoints: Int!
percent: Int!
storyPoints: Int!
total: Int!
}
"""
Writes are acknowledged immediately; the read model catches up asynchronously. Wait for a subscription event with version >= this version to see the change.
"""
type CommandResult {
id: ID!
key: String
version: Int!
}
type Comment {
author: UserRef!
"""Empty on a deleted comment kept for its replies"""
body: String!
createdAt: String!
"""Deleted, but kept (without its text) while it has replies"""
deleted: Boolean!
editedAt: String
id: ID!
issueId: ID!
"""The top-level comment it answers; null for a top-level one"""
replyTo: ID
version: Int!
}
type CommentChange {
action: String!
actorId: ID!
"""Null when deleted"""
comment: Comment
commentId: ID!
issueId: ID!
version: Int!
}
type CommentPage {
items: [Comment!]!
total: Int!
}
type CountByAssignee {
count: Int!
"""Null = unassigned"""
user: UserRef
}
type CountByKey {
count: Int!
key: String!
}
type CountByStatus {
count: Int!
"""Status id"""
key: String!
}
input CreateAutomationInput {
action: AutomationActionInput!
conditions: AutomationConditionsInput
name: String!
projectId: ID!
trigger: AutomationTriggerInput!
}
input CreateIssueInput {
"""An area id"""
area: String
assigneeId: ID
description: String
dueDate: String
"""Figma frame for UI changes"""
figmaUrl: String
labels: [String!]
"""Epic or ticket of the same project the new one breaks down"""
parentId: ID
priority: IssuePriority
projectId: ID!
releaseId: ID
"""When work should start (roadmap), YYYY-MM-DD"""
startDate: String
storyPoints: Int
title: String!
"""A ticket type id"""
type: String!
}
input CreateProjectInput {
description: String
"""Readable by anyone, also without signing in"""
isPublic: Boolean
"""2-10 chars, e.g. "TS" → tickets TS-1, TS-2..."""
key: String!
name: String!
}
input CreateReleaseInput {
description: String
"""e.g. v1.4.0"""
name: String!
projectId: ID!
targetDate: String
}
input CreateSprintInput {
"""YYYY-MM-DD, included"""
endDate: String!
goal: String
name: String!
projectId: ID!
"""YYYY-MM-DD"""
startDate: String!
}
input CreateWebhookInput {
"""Event names, family.* or *"""
events: [String!]!
projectId: ID!
url: String!
}
type CreatedResolved {
created: Int!
resolved: Int!
"""Monday of the week (YYYY-MM-DD)"""
week: String!
}
type CumulativeFlow {
dates: [String!]!
series: [FlowSeries!]!
}
"""A commit, branch or pull request that mentions the ticket"""
type DevLink {
at: String!
author: String
kind: DevLinkKind!
"""github, gitea or gitlab"""
provider: String!
"""Short SHA, branch or PR number"""
ref: String!
"""The project's name for the repository it came from"""
repository: String
state: DevLinkState
title: String!
url: String!
}
enum DevLinkKind {
BRANCH
COMMIT
PULL_REQUEST
}
enum DevLinkState {
CLOSED
MERGED
OPEN
}
type DurationStats {
averageDays: Float
count: Int!
"""85% of tickets take at most this long"""
p85Days: Float
}
"""A top-level ticket that groups others, with their progress"""
type Epic {
issue: Issue!
progress: ChildProgress!
}
type FlowSeries {
counts: [Int!]!
status: String!
}
"""
Webhooks from GitHub, Gitea or GitLab: commits, branches and pull requests naming a ticket key are linked to it
"""
type GitIntegration {
"""On while there is at least one repository"""
enabled: Boolean!
repositories: [GitRepository!]!
"""Path of the webhook on this API, the same for every repository"""
webhookPath: String!
}
"""A repository whose webhooks the project accepts"""
type GitRepository {
createdAt: String!
id: ID!
"""The project's name for it: api, web, admin…"""
name: String!
"""Webhook secret of this repository; only owners and admins see it"""
secret: String
}
type Issue {
"""Statuses this ticket can move to next (project's workflow)"""
allowedTransitions: [String!]!
"""An area id"""
area: String
assignee: UserRef
attachments: [Attachment!]!
checklist: [ChecklistItem!]!
commentCount: Int!
comments(limit: Int! = 50, offset: Int! = 0): CommentPage!
createdAt: String!
description: String
"""Commits, branches and pull requests that mention it"""
devLinks: [DevLink!]!
dueDate: String
figmaUrl: String
"""History of this ticket"""
history(limit: Int! = 50): [Activity!]!
id: ID!
"""Human key, e.g. TS-42"""
key: String!
labels: [String!]!
"""Linked tickets I can see"""
linkedIssues: [Issue!]!
links: [IssueLink!]!
number: Int!
"""The epic or ticket this one breaks down"""
parent: IssueParent
priority: IssuePriority!
projectId: ID!
projectKey: String!
"""
Place in the backlog and in its board column (ascending, compare as text)
"""
rank: String!
release: ReleaseRef
reporter: UserRef!
sprint: SprintRef
"""When work should start (roadmap)"""
startDate: String
"""A status id of the project's settings"""
status: String!
statusCategory: StatusCategory!
storyPoints: Int
title: String!
"""In the trash since then; null when it is not"""
trashedAt: String
"""A ticket type id of the project's settings"""
type: String!
updatedAt: String!
version: Int!
"""People following the ticket"""
watchers: [UserRef!]!
}
type IssueChange {
action: String!
actorId: ID!
issue: Issue!
version: Int!
}
input IssueFilterInput {
areas: [String!]
assigneeId: ID
categories: [StatusCategory!]
"""Due on or after this day (YYYY-MM-DD)"""
dueFrom: String
"""Due on or before this day (YYYY-MM-DD)"""
dueTo: String
labels: [String!]
"""Only tickets in no sprint"""
noSprint: Boolean
"""Only the tickets hanging from this one"""
parentId: ID
priorities: [IssuePriority!]
projectId: ID!
releaseId: ID
"""Matches key, title or description"""
search: String
sort: IssueSort = RECENT
sprintId: ID
statuses: [String!]
types: [String!]
unassigned: Boolean
}
type IssueLink {
"""OUTWARD: this issue → other. INWARD: other → this issue."""
direction: LinkDirection!
issueId: ID!
issueKey: String!
type: IssueLinkType!
}
enum IssueLinkType {
BLOCKS
DEPENDS_ON
DUPLICATES
RELATES_TO
TESTS
}
type IssuePage {
items: [Issue!]!
total: Int!
}
"""The ticket another one hangs from"""
type IssueParent {
id: ID!
key: String!
title: String!
}
enum IssuePriority {
CRITICAL
HIGH
LOW
LOWEST
MEDIUM
}
"""RECENT: last updated first. RANK: backlog order."""
enum IssueSort {
RANK
RECENT
}
"""What a new ticket of the type starts with"""
type IssueTemplate {
"""Steps added to every new ticket"""
checklist: [String!]!
"""Used when the ticket comes without a description"""
description: String
}
input IssueTemplateInput {
checklist: [String!]! = []
description: String
}
type IssueTypeOption {
archived: Boolean!
color: String!
icon: String!
id: String!
name: String!
template: IssueTemplate
}
input IssueTypeOptionInput {
archived: Boolean! = false
color: String!
icon: String!
id: String!
name: String!
template: IssueTemplateInput
}
enum LinkDirection {
INWARD
OUTWARD
}
input LinkIssuesInput {
issueId: ID!
targetIssueId: ID!
type: IssueLinkType!
}
type Me {
"""Roles inside the task-stream OAuth client"""
appRoles: [String!]!
email: String!
id: ID!
isActive: Boolean!
name: String!
"""Global roles in Pireon"""
roles: [String!]!
}
type Mutation {
"""Add a step to a ticket's checklist"""
addChecklistItem(input: AddChecklistItemInput!): CommandResult!
"""
Comment on a ticket, or answer a comment (replyTo; one level of replies)
"""
addComment(body: String!, issueId: ID!, replyTo: ID): CommandResult!
"""
Add a repository with its own secret (the first turns the integration on)
"""
addGitRepository(name: String!, projectId: ID!): GitRepository!
"""Add a Pireon user to the project"""
addProjectMember(input: ProjectMemberInput!): CommandResult!
archiveRelease(releaseId: ID!): CommandResult!
"""Assign (or unassign with null) a project member"""
assignIssue(assigneeId: ID, issueId: ID!): CommandResult!
"""
The same change on up to 100 tickets; each goes through the normal rules and may refuse on its own
"""
bulkUpdateIssues(input: BulkUpdateIssuesInput!): BulkResult!
"""Move a ticket through the workflow (incl. QA)"""
changeIssueStatus(input: ChangeIssueStatusInput!): CommandResult!
changeProjectMemberRole(input: ProjectMemberInput!): CommandResult!
"""
Close the sprint under way. Unfinished tickets move to carryOverToSprintId, or back to the backlog when it is null.
"""
closeSprint(carryOverToSprintId: ID, sprintId: ID!): CommandResult!
"""
Add a rule. It acts as TaskStream, within the workflow, and what it does triggers no other rule.
"""
createAutomation(input: CreateAutomationInput!): Automation!
createIssue(input: CreateIssueInput!): CommandResult!
createProject(input: CreateProjectInput!): CommandResult!
createRelease(input: CreateReleaseInput!): CommandResult!
"""Plan a sprint (owners and admins)"""
createSprint(input: CreateSprintInput!): CommandResult!
createWebhook(input: CreateWebhookInput!): WebhookCreated!
deleteAutomation(automationId: ID!): Boolean!
"""Author or project admin"""
deleteComment(commentId: ID!): CommandResult!
"""
Delete the project (owner only), with its tickets, comments and releases. `confirmKey` must be the project key.
"""
deleteProject(confirmKey: String!, projectId: ID!): CommandResult!
"""Delete a view: whoever saved it, or an admin if it is shared"""
deleteSavedFilter(id: ID!): Boolean!
"""Delete a sprint that never started; its tickets go back to the backlog"""
deleteSprint(sprintId: ID!): CommandResult!
deleteWebhook(webhookId: ID!): Boolean!
editComment(body: String!, commentId: ID!): CommandResult!
"""Relate tickets, e.g. FE DEPENDS_ON BE, QA TESTS FE"""
linkIssues(input: LinkIssuesInput!): CommandResult!
"""Mark these as read, or all of them when `ids` is omitted"""
markNotificationsRead(ids: [ID!]): Boolean!
"""
Ship the release. Fails while it has unfinished tickets unless force = true.
"""
publishRelease(force: Boolean! = false, releaseId: ID!): CommandResult!
"""Move a ticket in the backlog, between two others of the same project"""
rankIssue(input: RankIssueInput!): CommandResult!
"""
Remove a file from a ticket (whoever uploaded it, or an owner/admin). Upload with the REST API.
"""
removeAttachment(attachmentId: ID!, issueId: ID!): CommandResult!
removeChecklistItem(issueId: ID!, itemId: ID!): CommandResult!
"""Remove a repository; what it linked stays on the tickets"""
removeGitRepository(projectId: ID!, repositoryId: ID!): Boolean!
removeProjectMember(projectId: ID!, userId: ID!): CommandResult!
"""Back from the trash"""
restoreIssue(issueId: ID!): CommandResult!
"""A new secret for a repository; the old one stops working"""
rotateGitRepositorySecret(projectId: ID!, repositoryId: ID!): GitRepository!
"""Save the current board filters under a name (members of the project)"""
saveFilter(input: SaveFilterInput!): ID!
"""
Place a ticket under an epic or another ticket of the same project (null: back to the top). Three levels at most: epic → ticket → subtask.
"""
setIssueParent(issueId: ID!, parentId: ID): CommandResult!
"""Put a ticket in a release (null removes it)"""
setIssueRelease(issueId: ID!, releaseId: ID): CommandResult!
"""Put a ticket in a sprint (null: back to the backlog)"""
setIssueSprint(issueId: ID!, sprintId: ID): CommandResult!
"""Start a planned sprint (only one under way per project)"""
startSprint(sprintId: ID!): CommandResult!
"""Send a ping now and tell how it went"""
testWebhook(webhookId: ID!): WebhookDelivery!
"""
To the trash (whoever opened it, or an owner/admin): hidden everywhere, deleted for good after 30 days
"""
trashIssue(issueId: ID!): CommandResult!
unlinkIssues(input: LinkIssuesInput!): CommandResult!
"""Stop following a ticket"""
unwatchIssue(issueId: ID!): CommandResult!
"""Rename, pause or resume"""
updateAutomation(active: Boolean, automationId: ID!, name: String): Automation!
"""Reword, tick or untick a checklist step"""
updateChecklistItem(input: UpdateChecklistItemInput!): CommandResult!
updateIssue(input: UpdateIssueInput!): CommandResult!
updateNotificationSettings(email: Boolean!): NotificationSettings!
updateProject(input: UpdateProjectInput!): CommandResult!
"""
Replace statuses, transitions, ticket types and areas (owners and admins). Values can be archived, not deleted.
"""
updateProjectSettings(projectId: ID!, settings: ProjectSettingsInput!): CommandResult!
updateRelease(input: UpdateReleaseInput!): CommandResult!
updateSprint(input: UpdateSprintInput!): CommandResult!
updateWebhook(input: UpdateWebhookInput!): Webhook!
"""
Follow a ticket: be told when it moves, is reassigned or gets a comment
"""
watchIssue(issueId: ID!): CommandResult!
"""
Write the release notes (Markdown; null removes them). Also after shipping.
"""
writeReleaseNotes(notes: String, releaseId: ID!): CommandResult!
}
type MyNotifications {
items: [Notification!]!
"""All my unread ones, not just these"""
unread: Int!
}
type Notification {
actor: UserRef!
createdAt: String!
id: ID!
issueId: ID
issueKey: String
kind: NotificationKind!
projectId: ID!
projectKey: String!
"""Null: unread"""
readAt: String
summary: String!
}
"""Why someone is told"""
enum NotificationKind {
ADDED_TO_PROJECT
ASSIGNED
COMMENTED
MENTIONED
QA_FAILED
REMINDER
REPLIED
STATUS_CHANGED
WATCHED
}
type NotificationSettings {
"""Copies by e-mail"""
email: Boolean!
"""Whether this installation can send e-mail at all"""
emailAvailable: Boolean!
}
type Project {
"""
Statistics of the last `days` days (7-365): created vs resolved, cumulative flow, cycle/lead time, throughput and QA
"""
analytics(days: Int! = 90): ProjectAnalytics!
"""Kanban board, one column per status"""
board(
area: String
assigneeId: ID
labels: [String!]
perColumn: Int! = 50
priorities: [IssuePriority!]
releaseId: ID
"""Matches key, title or description"""
search: String
sprintId: ID
types: [String!]
unassigned: Boolean
): [BoardColumn!]!
createdAt: String!
description: String
id: ID!
"""Anyone can read it, also without signing in"""
isPublic: Boolean!
key: String!
members: [ProjectMember!]!
name: String!
owner: UserRef!
releases: [Release!]!
settings: ProjectSettings!
"""Project tracking dashboard"""
stats: ProjectStats!
updatedAt: String!
version: Int!
}
type ProjectAnalytics {
createdVsResolved: [CreatedResolved!]!
"""Tickets in each status at the end of every day"""
cumulativeFlow: CumulativeFlow!
"""Start of work → done"""
cycleTime: DurationStats!
from: String!
"""Creation → done"""
leadTime: DurationStats!
qa: QaStats!
"""Finished per person and week"""
throughput: [Throughput!]!
to: String!
}
type ProjectChange {
action: String!
actorId: ID!
project: Project!
version: Int!
}
type ProjectMember {
role: ProjectRole!
user: UserRef!
}
input ProjectMemberInput {
projectId: ID!
role: ProjectRole! = MEMBER
"""Pireon user id"""
userId: ID!
}
enum ProjectRole {
ADMIN
MEMBER
OWNER
VIEWER
}
"""Statuses (board order), transitions, ticket types and areas"""
type ProjectSettings {
areas: [AreaOption!]!
issueTypes: [IssueTypeOption!]!
statuses: [WorkflowStatus!]!
transitions: [StatusTransitions!]!
}
"""
The whole configuration (replaces the previous one). Statuses go in board order.
"""
input ProjectSettingsInput {
areas: [AreaOptionInput!]!
issueTypes: [IssueTypeOptionInput!]!
statuses: [WorkflowStatusInput!]!
transitions: [StatusTransitionsInput!]!
}
type ProjectStats {
byArea: [CountByKey!]!
"""Open tickets per person"""
byAssignee: [CountByAssignee!]!
byPriority: [CountByKey!]!
byStatus: [CountByStatus!]!
byType: [CountByKey!]!
open: Int!
total: Int!
}
type QaStats {
failed: Int!
failureRate: Float
passed: Int!
}
type Query {
"""Project activity feed (newest first)"""
activity(
"""ISO date cursor"""
before: String
issueId: ID
limit: Int! = 50
projectId: ID!
): [Activity!]!
automations(projectId: ID!): [Automation!]!
"""
A project's epics: top-level tickets that group others, with the progress of those
"""
epics(projectId: ID!): [Epic!]!
gitIntegration(projectId: ID!): GitIntegration!
issue(
"""Issue id or key (e.g. "TS-42")"""
idOrKey: String!
): Issue!
issues(filter: IssueFilterInput!, limit: Int! = 50, offset: Int! = 0): IssuePage!
"""The authenticated user"""
me: Me!
"""
Tickets across all my projects: assigned to me (default) or any (e.g. categories [QA])
"""
myIssues(
assignedToMe: Boolean! = true
categories: [StatusCategory!]
limit: Int! = 50
offset: Int! = 0
"""Matches key, title or description (global search)"""
search: String
statuses: [String!]
): IssuePage!
"""My notifications, newest first, and how many are unread"""
myNotifications(limit: Int! = 30, unreadOnly: Boolean! = false): MyNotifications!
"""Projects where I am a member"""
myProjects: [Project!]!
notificationSettings: NotificationSettings!
"""A project of mine, or any public one (no sign-in needed)"""
project(
"""Project id or key (e.g. "TS")"""
idOrKey: String!
): Project!
"""Projects anyone can read, also without signing in"""
publicProjects: [Project!]!
release(id: ID!): Release!
"""My views of the project's board, then the shared ones"""
savedFilters(projectId: ID!): [SavedFilter!]!
sprint(id: ID!): Sprint!
"""
A project's sprints: the one under way, the planned ones, then the closed ones
"""
sprints(projectId: ID!): [Sprint!]!
"""A project's tickets in the trash, newest first"""
trash(projectId: ID!): [Issue!]!
"""Planned releases of all my projects, soonest target date first"""
upcomingReleases(limit: Int! = 10): [Release!]!
user(id: String!): User
"""Search users by name or email (to assign / add members)"""
users(limit: Int! = 20, search: String! = ""): [User!]!
"""Event names a webhook can subscribe to (also family.* and *)"""
webhookEvents: [String!]!
webhooks(projectId: ID!): [Webhook!]!
}
input RankIssueInput {
"""The ticket that ends up right above (null: the top)"""
aboveIssueId: ID
"""The ticket that ends up right below (null: the bottom)"""
belowIssueId: ID
issueId: ID!
}
type Release {
"""Scope vs finished tickets, day by day"""
burnup: ReleaseBurnup!
createdAt: String!
description: String
id: ID!
"""Tickets included in this release"""
issues(limit: Int! = 100, offset: Int! = 0): IssuePage!
name: String!
"""What shipped, told for people (Markdown)"""
notes: String
"""
A Markdown draft of the notes from its finished tickets, by type (not saved)
"""
notesDraft: String!
progress: ReleaseProgress!
projectId: ID!
releasedAt: String
status: ReleaseStatus!
targetDate: String
version: Int!
}
type ReleaseBurnup {
dates: [String!]!
done: [Int!]!
releaseId: ID!
"""Tickets in the release (not cancelled)"""
scope: [Int!]!
targetDate: String
}
type ReleaseChange {
action: String!
actorId: ID!
release: Release!
version: Int!
}
type ReleaseProgress {
byStatus: [CountByStatus!]!
finished: Int!
percent: Int!
total: Int!
}
type ReleaseRef {
id: ID!
name: String!
}
enum ReleaseStatus {
ARCHIVED
PLANNED
RELEASED
}
input SaveFilterInput {
criteria: SavedFilterCriteriaInput!
name: String!
projectId: ID!
"""Visible to the whole project (members, not viewers, share)"""
shared: Boolean! = false
}
"""
A named view of the board: private to whoever saved it, or shared with the project
"""
type SavedFilter {
createdAt: String!
criteria: SavedFilterCriteria!
id: ID!
name: String!
owner: UserRef!
projectId: ID!
shared: Boolean!
}
"""What a saved view narrows the board to; empty: everything"""
type SavedFilterCriteria {
areas: [String!]
assigneeId: ID
labels: [String!]
priorities: [IssuePriority!]
releaseId: ID
search: String
types: [String!]
unassigned: Boolean
}
input SavedFilterCriteriaInput {
areas: [String!]
assigneeId: ID
labels: [String!]
priorities: [IssuePriority!]
releaseId: ID
search: String
types: [String!]
unassigned: Boolean
}
"""A time-boxed iteration: the tickets the team commits to"""
type Sprint {
burndown: SprintBurndown!
closedAt: String
createdAt: String!
"""Last day (included), YYYY-MM-DD"""
endDate: String!
goal: String
id: ID!
"""Tickets in this sprint, in backlog order"""
issues(limit: Int! = 100, offset: Int! = 0): IssuePage!
name: String!
progress: SprintProgress!
projectId: ID!
"""First day, YYYY-MM-DD"""
startDate: String!
startedAt: String
status: SprintStatus!
version: Int!
}
"""
Per day of the sprint: tickets in it, still open, and their points (null: days to come). `ideal` falls from the first day to zero.
"""
type SprintBurndown {
dates: [String!]!
ideal: [Float!]!
remaining: [Int]!
remainingPoints: [Int]!
scope: [Int]!
sprintId: ID!
}
type SprintChange {
action: String!
actorId: ID!
"""Null: deleted"""
sprint: Sprint
sprintId: ID!
version: Int!
}
type SprintProgress {
"""Done or cancelled"""
finished: Int!
finishedStoryPoints: Int!
percent: Int!
storyPoints: Int!
total: Int!
}
type SprintRef {
id: ID!
name: String!
}
"""PLANNED, ACTIVE (one per project at a time) or CLOSED"""
enum SprintStatus {
ACTIVE
CLOSED
PLANNED
}
"""
What a status means, whatever each project calls it. DONE and CANCELLED are finished.
"""
enum StatusCategory {
CANCELLED
DONE
IN_PROGRESS
QA
TODO
}
type StatusTransitions {
from: String!
to: [String!]!
}
input StatusTransitionsInput {
from: String!
to: [String!]!
}
type Subscription {
"""Live activity feed"""
activityAdded(projectId: ID!): Activity!
commentChanged(issueId: ID!): CommentChange!
"""Tickets created/updated/moved in a project (board in realtime)"""
issueChanged(projectId: ID!): IssueChange!
"""Projects I am added to / removed from"""
myProjectsChanged: ProjectChange!
"""My notifications, as they happen"""
notificationAdded: Notification!
projectChanged(projectId: ID!): ProjectChange!
releaseChanged(projectId: ID!): ReleaseChange!
sprintChanged(projectId: ID!): SprintChange!
}
type Throughput {
count: Int!
user: UserRef
week: String!
}
input UpdateChecklistItemInput {
done: Boolean
issueId: ID!
itemId: ID!
text: String
}
input UpdateIssueInput {
"""An area id"""
area: String
description: String
dueDate: String
"""Figma frame for UI changes"""
figmaUrl: String
issueId: ID!
labels: [String!]
priority: IssuePriority
"""When work should start (roadmap), YYYY-MM-DD"""
startDate: String
storyPoints: Int
title: String
type: String
}
input UpdateProjectInput {
description: String
isPublic: Boolean
name: String
projectId: ID!
}
input UpdateReleaseInput {
description: String
name: String
releaseId: ID!
targetDate: String
}
input UpdateSprintInput {
endDate: String
goal: String
name: String
sprintId: ID!
startDate: String
}
input UpdateWebhookInput {
active: Boolean
events: [String!]
url: String
webhookId: ID!
}
"""User managed by the Pireon identity server"""
type User {
email: String!
id: ID!
isActive: Boolean!
name: String!
}
type UserRef {
id: ID!
name: String!
}
"""
Where the project tells another system what happened (signed POST, HMAC-SHA256)
"""
type Webhook {
active: Boolean!
createdAt: String!
createdBy: UserRef!
"""Event names, family.* or *"""
events: [String!]!
id: ID!
lastDelivery: WebhookDelivery
projectId: ID!
url: String!
}
type WebhookCreated {
id: ID!
"""Signs every delivery. Shown only now: keep it."""
secret: String!
}
type WebhookDelivery {
at: String!
error: String
event: String!
ok: Boolean!
"""HTTP status"""
status: Int
}
type WorkflowStatus {
"""No new tickets or transitions into it"""
archived: Boolean!
category: StatusCategory!
"""Colour token: slate, violet, green…"""
color: String!
"""Stable id stored on tickets, e.g. IN_REVIEW"""
id: String!
name: String!
"""Entering it needs a reason"""
requiresReason: Boolean!
"""
Work-in-progress limit: most tickets the column should hold (a warning, not a lock)
"""
wipLimit: Int
}
input WorkflowStatusInput {
archived: Boolean! = false
category: StatusCategory!
color: String!
id: String!
name: String!
requiresReason: Boolean! = false
"""Work-in-progress limit (null: none)"""
wipLimit: Int
}