feat: pinned tickets, at hand on the home page and in search
Each person pins up to 20 tickets from the ticket's page («Fijar»). They
show as a strip under the projects on the home page and in the search
palette before typing. Private and without history, like the views of
«my work» (Mongo `pinned_issues`); tickets in the trash or out of reach
are left out, and when the list is full the unreadable ones are dropped
first.
API: GET /api/me/pins, PUT/DELETE /api/issues/{issue}/pin; GraphQL
myPins, pinIssue, unpinIssue and Issue.pinned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ import {
|
||||
import {
|
||||
CommentsService,
|
||||
IssuesService,
|
||||
PinsService,
|
||||
PresenceService,
|
||||
ProjectsService,
|
||||
} from '@task-stream/api/tracker/application';
|
||||
@@ -94,6 +95,7 @@ export class IssuesController {
|
||||
private readonly refs: Refs,
|
||||
private readonly presence: PresenceService,
|
||||
private readonly projects: ProjectsService,
|
||||
private readonly pins: PinsService,
|
||||
) {}
|
||||
|
||||
@Get('me/home')
|
||||
@@ -163,6 +165,41 @@ export class IssuesController {
|
||||
await this.presence.leave(me.id, await this.refs.issueId(me.id, issue));
|
||||
}
|
||||
|
||||
@Get('me/pins')
|
||||
@ApiOperation({
|
||||
summary: 'My pinned tickets, most recently pinned first',
|
||||
description:
|
||||
'Across my projects; tickets in the trash or out of my reach are left out.',
|
||||
})
|
||||
@ApiOkResponse({ type: [IssueDto] })
|
||||
@ApiReadErrors()
|
||||
async myPins(@CurrentUser() me: User) {
|
||||
return this.refs.issueDtos(await this.pins.mine(me.id), viewerOf(me));
|
||||
}
|
||||
|
||||
@Put('issues/:issue/pin')
|
||||
@HttpCode(204)
|
||||
@ISSUE
|
||||
@ApiOperation({
|
||||
summary: 'Pin a ticket: keep it at hand on my home page and in search',
|
||||
description: 'Private to me; at most 20. Pinning it again changes nothing.',
|
||||
})
|
||||
@ApiNoContentResponse()
|
||||
@ApiCommandErrors()
|
||||
async pin(@CurrentUser() me: User, @Param('issue') issue: string) {
|
||||
await this.pins.pin(me.id, await this.refs.issueId(me.id, issue), true);
|
||||
}
|
||||
|
||||
@Delete('issues/:issue/pin')
|
||||
@HttpCode(204)
|
||||
@ISSUE
|
||||
@ApiOperation({ summary: 'Unpin a ticket' })
|
||||
@ApiNoContentResponse()
|
||||
@ApiCommandErrors()
|
||||
async unpin(@CurrentUser() me: User, @Param('issue') issue: string) {
|
||||
await this.pins.pin(me.id, await this.refs.issueId(me.id, issue), false);
|
||||
}
|
||||
|
||||
@Put('issues/:issue/watch')
|
||||
@ISSUE
|
||||
@ApiOperation({
|
||||
|
||||
Reference in New Issue
Block a user