feat: follow an epic with everything under it
«Seguir todo» on a ticket with subtasks (and on each epic of the Epics
page) tells you of it and of every ticket hanging from it, at any depth,
also the ones added later: their moves, assignments, comments and plan
changes, as a follower of each, plus when a ticket is placed under it.
Guests of a private project are left out. Personal, no history (Mongo
`tree_follows`).
API: followTree / unfollowTree, Issue.followingTree, PUT/DELETE
/api/issues/{issue}/follow-tree. MCP: watch_issue with tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -688,6 +688,7 @@ export type IssueSummaryFieldsFragment = {
|
||||
|
||||
export type IssueFieldsFragment = {
|
||||
pinned: boolean;
|
||||
followingTree: boolean;
|
||||
description: string | null;
|
||||
figmaUrl: string | null;
|
||||
createdAt: string;
|
||||
@@ -933,6 +934,7 @@ export type IssueQueryVariables = Exact<{
|
||||
export type IssueQuery = {
|
||||
issue: {
|
||||
pinned: boolean;
|
||||
followingTree: boolean;
|
||||
description: string | null;
|
||||
figmaUrl: string | null;
|
||||
createdAt: string;
|
||||
@@ -1151,6 +1153,18 @@ export type MyPinsQuery = {
|
||||
}>;
|
||||
};
|
||||
|
||||
export type FollowTreeMutationVariables = Exact<{
|
||||
issueId: string;
|
||||
}>;
|
||||
|
||||
export type FollowTreeMutation = { followTree: boolean };
|
||||
|
||||
export type UnfollowTreeMutationVariables = Exact<{
|
||||
issueId: string;
|
||||
}>;
|
||||
|
||||
export type UnfollowTreeMutation = { unfollowTree: boolean };
|
||||
|
||||
export type PinIssueMutationVariables = Exact<{
|
||||
issueId: string;
|
||||
}>;
|
||||
@@ -1321,6 +1335,7 @@ export type EpicsQueryVariables = Exact<{
|
||||
export type EpicsQuery = {
|
||||
epics: Array<{
|
||||
issue: {
|
||||
followingTree: boolean;
|
||||
id: string;
|
||||
projectId: string;
|
||||
key: string;
|
||||
@@ -3820,6 +3835,7 @@ export const IssueFieldsFragmentDoc = {
|
||||
name: { kind: 'Name', value: 'IssueSummaryFields' },
|
||||
},
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'pinned' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'followingTree' } },
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'decisions' },
|
||||
@@ -6420,6 +6436,7 @@ export const IssueDocument = {
|
||||
name: { kind: 'Name', value: 'IssueSummaryFields' },
|
||||
},
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'pinned' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'followingTree' } },
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'decisions' },
|
||||
@@ -7452,6 +7469,93 @@ export const MyPinsDocument = {
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<MyPinsQuery, MyPinsQueryVariables>;
|
||||
export const FollowTreeDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'mutation',
|
||||
name: { kind: 'Name', value: 'FollowTree' },
|
||||
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: 'followTree' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'issueId' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'issueId' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<FollowTreeMutation, FollowTreeMutationVariables>;
|
||||
export const UnfollowTreeDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'mutation',
|
||||
name: { kind: 'Name', value: 'UnfollowTree' },
|
||||
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: 'unfollowTree' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'issueId' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'issueId' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<
|
||||
UnfollowTreeMutation,
|
||||
UnfollowTreeMutationVariables
|
||||
>;
|
||||
export const PinIssueDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
@@ -8633,6 +8737,10 @@ export const EpicsDocument = {
|
||||
kind: 'FragmentSpread',
|
||||
name: { kind: 'Name', value: 'IssueSummaryFields' },
|
||||
},
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'followingTree' },
|
||||
},
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'links' },
|
||||
|
||||
Reference in New Issue
Block a user