feat: release notes

Each release can carry notes in Markdown, written before or after it
ships. A draft is generated from its finished tickets grouped by type, to
edit and copy from the releases page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:19:23 +02:00
parent 45a3dc1e16
commit 24b37b6628
40 changed files with 1251 additions and 31 deletions

View File

@@ -368,6 +368,7 @@ export type ReleaseFieldsFragment = {
targetDate: string | null;
status: ReleaseStatus;
releasedAt: string | null;
notes: string | null;
};
export type ActivityFieldsFragment = {
@@ -1148,6 +1149,7 @@ export type ReleasesQuery = {
targetDate: string | null;
status: ReleaseStatus;
releasedAt: string | null;
notes: string | null;
progress: { total: number; finished: number; percent: number };
}>;
};
@@ -1208,6 +1210,7 @@ export type UpcomingReleasesQuery = {
targetDate: string | null;
status: ReleaseStatus;
releasedAt: string | null;
notes: string | null;
progress: { total: number; finished: number; percent: number };
}>;
};
@@ -1229,6 +1232,23 @@ export type ReleaseBurnupQuery = {
};
};
export type ReleaseNotesDraftQueryVariables = Exact<{
id: string;
}>;
export type ReleaseNotesDraftQuery = {
release: { id: string; notesDraft: string };
};
export type WriteReleaseNotesMutationVariables = Exact<{
releaseId: string;
notes?: string | null | undefined;
}>;
export type WriteReleaseNotesMutation = {
writeReleaseNotes: { id: string; key: string | null; version: number };
};
export type SavedFilterFieldsFragment = {
id: string;
projectId: string;
@@ -1489,6 +1509,7 @@ export type ReleaseChangedSubscription = {
targetDate: string | null;
status: ReleaseStatus;
releasedAt: string | null;
notes: string | null;
};
};
};
@@ -2119,6 +2140,7 @@ export const ReleaseFieldsFragmentDoc = {
{ kind: 'Field', name: { kind: 'Name', value: 'targetDate' } },
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
{ kind: 'Field', name: { kind: 'Name', value: 'releasedAt' } },
{ kind: 'Field', name: { kind: 'Name', value: 'notes' } },
],
},
},
@@ -7298,6 +7320,7 @@ export const ReleasesDocument = {
{ kind: 'Field', name: { kind: 'Name', value: 'targetDate' } },
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
{ kind: 'Field', name: { kind: 'Name', value: 'releasedAt' } },
{ kind: 'Field', name: { kind: 'Name', value: 'notes' } },
],
},
},
@@ -7741,6 +7764,7 @@ export const UpcomingReleasesDocument = {
{ kind: 'Field', name: { kind: 'Name', value: 'targetDate' } },
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
{ kind: 'Field', name: { kind: 'Name', value: 'releasedAt' } },
{ kind: 'Field', name: { kind: 'Name', value: 'notes' } },
],
},
},
@@ -7814,6 +7838,141 @@ export const ReleaseBurnupDocument = {
},
],
} as unknown as DocumentNode<ReleaseBurnupQuery, ReleaseBurnupQueryVariables>;
export const ReleaseNotesDraftDocument = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: { kind: 'Name', value: 'ReleaseNotesDraft' },
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
type: {
kind: 'NonNullType',
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'release' },
arguments: [
{
kind: 'Argument',
name: { kind: 'Name', value: 'id' },
value: {
kind: 'Variable',
name: { kind: 'Name', value: 'id' },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
{ kind: 'Field', name: { kind: 'Name', value: 'notesDraft' } },
],
},
},
],
},
},
],
} as unknown as DocumentNode<
ReleaseNotesDraftQuery,
ReleaseNotesDraftQueryVariables
>;
export const WriteReleaseNotesDocument = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'mutation',
name: { kind: 'Name', value: 'WriteReleaseNotes' },
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: {
kind: 'Variable',
name: { kind: 'Name', value: 'releaseId' },
},
type: {
kind: 'NonNullType',
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
},
},
{
kind: 'VariableDefinition',
variable: {
kind: 'Variable',
name: { kind: 'Name', value: 'notes' },
},
type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'writeReleaseNotes' },
arguments: [
{
kind: 'Argument',
name: { kind: 'Name', value: 'releaseId' },
value: {
kind: 'Variable',
name: { kind: 'Name', value: 'releaseId' },
},
},
{
kind: 'Argument',
name: { kind: 'Name', value: 'notes' },
value: {
kind: 'Variable',
name: { kind: 'Name', value: 'notes' },
},
},
],
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<
WriteReleaseNotesMutation,
WriteReleaseNotesMutationVariables
>;
export const SavedFiltersDocument = {
kind: 'Document',
definitions: [
@@ -9123,6 +9282,7 @@ export const ReleaseChangedDocument = {
{ kind: 'Field', name: { kind: 'Name', value: 'targetDate' } },
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
{ kind: 'Field', name: { kind: 'Name', value: 'releasedAt' } },
{ kind: 'Field', name: { kind: 'Name', value: 'notes' } },
],
},
},