feat: mentions and following tickets

Mention project members in comments with @, follow and unfollow tickets,
and get told when something changes on the tickets you follow. Commenting
on a ticket starts following it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 09:41:32 +02:00
parent efa06a0723
commit 88928b402f
49 changed files with 1318 additions and 41 deletions

View File

@@ -88,6 +88,9 @@ fragment IssueFields on Issue {
issueId
issueKey
}
watchers {
...UserRefFields
}
attachments {
id
fileName

View File

@@ -248,6 +248,7 @@ export type IssueFieldsFragment = {
issueId: string;
issueKey: string;
}>;
watchers: Array<{ id: string; name: string }>;
attachments: Array<{
id: string;
fileName: string;
@@ -362,6 +363,7 @@ export type IssueQuery = {
issueId: string;
issueKey: string;
}>;
watchers: Array<{ id: string; name: string }>;
attachments: Array<{
id: string;
fileName: string;
@@ -451,6 +453,22 @@ export type UnlinkIssuesMutation = {
unlinkIssues: { id: string; key: string | null; version: number };
};
export type WatchIssueMutationVariables = Exact<{
issueId: string;
}>;
export type WatchIssueMutation = {
watchIssue: { id: string; key: string | null; version: number };
};
export type UnwatchIssueMutationVariables = Exact<{
issueId: string;
}>;
export type UnwatchIssueMutation = {
unwatchIssue: { id: string; key: string | null; version: number };
};
export type SetIssueReleaseMutationVariables = Exact<{
issueId: string;
releaseId?: string | null | undefined;
@@ -1400,6 +1418,19 @@ export const IssueFieldsFragmentDoc = {
],
},
},
{
kind: 'Field',
name: { kind: 'Name', value: 'watchers' },
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'FragmentSpread',
name: { kind: 'Name', value: 'UserRefFields' },
},
],
},
},
{
kind: 'Field',
name: { kind: 'Name', value: 'attachments' },
@@ -2066,6 +2097,19 @@ export const IssueDocument = {
],
},
},
{
kind: 'Field',
name: { kind: 'Name', value: 'watchers' },
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'FragmentSpread',
name: { kind: 'Name', value: 'UserRefFields' },
},
],
},
},
{
kind: 'Field',
name: { kind: 'Name', value: 'attachments' },
@@ -2671,6 +2715,143 @@ export const UnlinkIssuesDocument = {
UnlinkIssuesMutation,
UnlinkIssuesMutationVariables
>;
export const WatchIssueDocument = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'mutation',
name: { kind: 'Name', value: 'WatchIssue' },
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: {
kind: 'Variable',
name: { kind: 'Name', value: 'issueId' },
},
type: {
kind: 'NonNullType',
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'watchIssue' },
arguments: [
{
kind: 'Argument',
name: { kind: 'Name', value: 'issueId' },
value: {
kind: 'Variable',
name: { kind: 'Name', value: 'issueId' },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'FragmentSpread',
name: { kind: 'Name', value: 'CommandResultFields' },
},
],
},
},
],
},
},
{
kind: 'FragmentDefinition',
name: { kind: 'Name', value: 'CommandResultFields' },
typeCondition: {
kind: 'NamedType',
name: { kind: 'Name', value: 'CommandResult' },
},
selectionSet: {
kind: 'SelectionSet',
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
{ kind: 'Field', name: { kind: 'Name', value: 'key' } },
{ kind: 'Field', name: { kind: 'Name', value: 'version' } },
],
},
},
],
} as unknown as DocumentNode<WatchIssueMutation, WatchIssueMutationVariables>;
export const UnwatchIssueDocument = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'mutation',
name: { kind: 'Name', value: 'UnwatchIssue' },
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: {
kind: 'Variable',
name: { kind: 'Name', value: 'issueId' },
},
type: {
kind: 'NonNullType',
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'unwatchIssue' },
arguments: [
{
kind: 'Argument',
name: { kind: 'Name', value: 'issueId' },
value: {
kind: 'Variable',
name: { kind: 'Name', value: 'issueId' },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'FragmentSpread',
name: { kind: 'Name', value: 'CommandResultFields' },
},
],
},
},
],
},
},
{
kind: 'FragmentDefinition',
name: { kind: 'Name', value: 'CommandResultFields' },
typeCondition: {
kind: 'NamedType',
name: { kind: 'Name', value: 'CommandResult' },
},
selectionSet: {
kind: 'SelectionSet',
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
{ kind: 'Field', name: { kind: 'Name', value: 'key' } },
{ kind: 'Field', name: { kind: 'Name', value: 'version' } },
],
},
},
],
} as unknown as DocumentNode<
UnwatchIssueMutation,
UnwatchIssueMutationVariables
>;
export const SetIssueReleaseDocument = {
kind: 'Document',
definitions: [

View File

@@ -66,6 +66,18 @@ mutation UnlinkIssues($input: LinkIssuesInput!) {
}
}
mutation WatchIssue($issueId: ID!) {
watchIssue(issueId: $issueId) {
...CommandResultFields
}
}
mutation UnwatchIssue($issueId: ID!) {
unwatchIssue(issueId: $issueId) {
...CommandResultFields
}
}
mutation SetIssueRelease($issueId: ID!, $releaseId: ID) {
setIssueRelease(issueId: $issueId, releaseId: $releaseId) {
...CommandResultFields