feat: attachments on tickets and comments
Files are uploaded over REST, stored on disk (a volume in Docker) and recorded on the ticket as events; the bytes are written first, so no attachment ever points at a missing file. Only images, video, audio, PDF and plain text are shown inline, everything with nosniff and a sandbox CSP. The web shows thumbnails, uploads by drag and drop or by pasting a screenshot, and attaches files to new comments. Also adds `nx run api:contracts`, which writes schema.gql and openapi.json without starting the API or any database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -65,6 +65,18 @@ export interface IssuePage {
|
||||
total: number;
|
||||
}
|
||||
|
||||
/** A file on a ticket (or under one of its comments). */
|
||||
export interface Attachment {
|
||||
id: string;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
/** Bytes. */
|
||||
size: number;
|
||||
uploadedBy: UserRef;
|
||||
uploadedAt: string;
|
||||
commentId: string | null;
|
||||
}
|
||||
|
||||
export interface Issue extends IssueSummary {
|
||||
description: string | null;
|
||||
reporter: UserRef;
|
||||
@@ -72,6 +84,7 @@ export interface Issue extends IssueSummary {
|
||||
storyPoints: number | null;
|
||||
dueDate: string | null;
|
||||
links: IssueLink[];
|
||||
attachments: Attachment[];
|
||||
allowedTransitions: string[];
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
Activity,
|
||||
Attachment,
|
||||
BoardColumn,
|
||||
Comment,
|
||||
CommandResult,
|
||||
@@ -93,6 +94,21 @@ export abstract class CommentsGateway {
|
||||
abstract remove(commentId: string): Observable<CommandResult>;
|
||||
}
|
||||
|
||||
/** A ticket's files. Uploads and downloads go through the REST API. */
|
||||
export abstract class AttachmentsGateway {
|
||||
abstract upload(
|
||||
issueId: string,
|
||||
file: File,
|
||||
commentId?: string | null,
|
||||
): Observable<CommandResult>;
|
||||
/** The file's bytes, to show (images) or save. */
|
||||
abstract download(issueId: string, attachment: Attachment): Observable<Blob>;
|
||||
abstract remove(
|
||||
issueId: string,
|
||||
attachmentId: string,
|
||||
): Observable<CommandResult>;
|
||||
}
|
||||
|
||||
export abstract class ReleasesGateway {
|
||||
abstract list(projectId: string): Observable<Release[]>;
|
||||
/** Planned releases of all my projects, soonest target date first. */
|
||||
|
||||
Reference in New Issue
Block a user