feat(web): dependencies between epics on the roadmap

Arrows from an epic to the ones that wait for it («bloquea» / «depende
de»), drawn over the bars; dashed red, plus a note in words, when one
starts before the epic blocking it ends. The next batch and the ideas
kept or dropped are written down in docs/10-futuro.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 10:00:14 +02:00
parent f7e850068b
commit 21bc598590
14 changed files with 397 additions and 28 deletions

View File

@@ -50,7 +50,12 @@ import {
UpdateIssueDocument,
} from '../graphql/generated';
import { GraphqlOperations } from './graphql-operations';
import { toCommandResult, toIssue, toIssueSummary } from './mappers';
import {
toCommandResult,
toIssue,
toIssueLink,
toIssueSummary,
} from './mappers';
@Injectable()
export class GraphqlIssuesGateway extends IssuesGateway {
@@ -214,6 +219,7 @@ export class GraphqlIssuesGateway extends IssuesGateway {
d.epics.map((epic) => ({
issue: toIssueSummary(epic.issue),
progress: { ...epic.progress },
links: epic.issue.links.map((l) => toIssueLink(l)),
})),
),
);

View File

@@ -3,6 +3,7 @@ import type {
Comment,
CommandResult,
Issue,
IssueLink,
IssueSummary,
Project,
ProjectSettings,
@@ -39,6 +40,12 @@ export const toProject = (p: ProjectFieldsFragment): Project => ({
export const toIssueSummary = (i: IssueSummaryFieldsFragment): IssueSummary =>
as<IssueSummary>(i);
export const toIssue = (i: IssueFieldsFragment): Issue => as<Issue>(i);
export const toIssueLink = (l: {
type: string;
direction: string;
issueId: string;
issueKey: string;
}): IssueLink => as<IssueLink>({ ...l });
export const toComment = (c: CommentFieldsFragment): Comment => c;
export const toActivity = (a: ActivityFieldsFragment): Activity => a;
export const toCommandResult = (

View File

@@ -1115,6 +1115,12 @@ export type EpicsQuery = {
startDate: string | null;
dueDate: string | null;
trashedAt: string | null;
links: Array<{
type: IssueLinkType;
direction: LinkDirection;
issueId: string;
issueKey: string;
}>;
assignee: { id: string; name: string } | null;
release: { id: string; name: string } | null;
sprint: { id: string; name: string } | null;
@@ -6783,6 +6789,31 @@ export const EpicsDocument = {
kind: 'FragmentSpread',
name: { kind: 'Name', value: 'IssueSummaryFields' },
},
{
kind: 'Field',
name: { kind: 'Name', value: 'links' },
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'type' },
},
{
kind: 'Field',
name: { kind: 'Name', value: 'direction' },
},
{
kind: 'Field',
name: { kind: 'Name', value: 'issueId' },
},
{
kind: 'Field',
name: { kind: 'Name', value: 'issueKey' },
},
],
},
},
],
},
},

View File

@@ -163,6 +163,12 @@ query Epics($projectId: ID!) {
epics(projectId: $projectId) {
issue {
...IssueSummaryFields
links {
type
direction
issueId
issueKey
}
}
progress {
total