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:
@@ -25,6 +25,8 @@ import {
|
||||
SearchIssuesDocument,
|
||||
SetIssueReleaseDocument,
|
||||
UnlinkIssuesDocument,
|
||||
UnwatchIssueDocument,
|
||||
WatchIssueDocument,
|
||||
UpdateIssueDocument,
|
||||
} from '../graphql/generated';
|
||||
import { GraphqlOperations } from './graphql-operations';
|
||||
@@ -119,6 +121,16 @@ export class GraphqlIssuesGateway extends IssuesGateway {
|
||||
.pipe(map((d) => toCommandResult(d.unlinkIssues)));
|
||||
}
|
||||
|
||||
watch(issueId: string, watching: boolean): Observable<CommandResult> {
|
||||
return watching
|
||||
? this.gql
|
||||
.mutate(WatchIssueDocument, { issueId })
|
||||
.pipe(map((d) => toCommandResult(d.watchIssue)))
|
||||
: this.gql
|
||||
.mutate(UnwatchIssueDocument, { issueId })
|
||||
.pipe(map((d) => toCommandResult(d.unwatchIssue)));
|
||||
}
|
||||
|
||||
setRelease(
|
||||
issueId: string,
|
||||
releaseId: string | null,
|
||||
|
||||
@@ -88,6 +88,9 @@ fragment IssueFields on Issue {
|
||||
issueId
|
||||
issueKey
|
||||
}
|
||||
watchers {
|
||||
...UserRefFields
|
||||
}
|
||||
attachments {
|
||||
id
|
||||
fileName
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user