/** * Issue-board (问题集) row shapes. * * Types are derived from the generated response envelopes wherever the backend * exposes one, so a schema change in `bun run gen:api` shows up here as a type * error instead of a runtime surprise. Paged payloads are typed as the generic * `Page` schema by the generator, so their item rows are declared structurally * (they mirror `IssueListItemDto` / `EventDto` in `lib/issues`). */ import type { EnvelopeBoardDto, EnvelopeCommentDto, EnvelopeIssueAttachmentDto, EnvelopeIssueDto, EnvelopeIssueUploadIntentDto, EnvelopeLabelDto, EnvelopeMilestoneDto, EnvelopeVecCommentTreeNode, IssuePriority, IssueState, UserDto, WatchMode, } from '@app/services/api' export type { IssuePriority, IssueState, UserDto, WatchMode } /** One issue board (`GET /issues/{space}/boards`). */ export type Board = NonNullable /** Full issue payload (`GET …/issues/{issue_id}`). */ export type IssueDetail = NonNullable /** Board label (`GET …/labels`). */ export type IssueLabel = NonNullable /** Milestone (`GET …/milestones`). */ export type Milestone = NonNullable /** One issue attachment (`GET …/issues/{id}/attachments`). */ export type IssueAttachment = NonNullable /** Presigned upload intent (`POST /issues/attachments`). */ export type IssueUploadIntent = NonNullable /** Issue comment, flat or inside a thread tree. */ export type IssueComment = NonNullable export type CommentNode = NonNullable[number]> /** Row of `GET …/issues` — the list endpoint omits body/description. */ export interface IssueListItem { id: string board_id: string number: number author?: UserDto | null title: string labels: IssueLabel[] milestone_id?: string | null priority: IssuePriority due_at?: string | null assignees: UserDto[] state: IssueState created_at: string updated_at?: string | null closed_at?: string | null } /** Activity line of `GET …/issues/{id}/events`. */ export interface IssueEvent { id: string issue_id?: string | null user?: UserDto | null event_type: string comment_id?: string | null commit_sha?: string | null old_title?: string | null new_title?: string | null old_ref?: string | null new_ref?: string | null content?: string | null created_at: string } /** Space member row used by the assignee picker. */ export interface SpaceMember { user?: UserDto | null alias_name?: string | null status?: string | null } /** Offset page as emitted by the backend (`{items,total,limit,offset}`). */ export interface IssuePage { items: T[] total: number limit: number offset: number } /** Filters accepted by `GET …/issues` (plus paging). */ export interface IssueQuery { state?: IssueState | 'all' q?: string /** Multi-select: any of these priorities matches. */ priorities?: IssuePriority[] labelIds?: string[] /** `none` is a UI-only token meaning "no milestone" (filtered client-side). */ milestoneIds?: string[] assigneeIds?: string[] authorId?: number sort?: IssueSort limit?: number offset?: number } /** Sort keys the backend understands; `created` is its default (newest first). */ export type IssueSort = 'created' | 'updated' | 'due' | 'priority' | 'number' /** * The board page's view state. The route persists it (see * `pages/workspace/model/board-location`); the feature components only ever * receive it as a plain object, so no UI slice depends on the page layer. */ export interface IssueBoardView { /** `board` = kanban grouped by priority, `list` = table. */ view: 'board' | 'list' state: IssueState | 'all' /** Title keyword (backend `q`). */ q: string /** Filter panel dimensions; empty arrays mean "no constraint". */ priorities: IssuePriority[] labelIds: string[] milestoneIds: string[] assigneeIds: string[] sort: IssueSort /** 1-based page within the filtered result set. */ page: number /** Open issue: board-scoped number (`42`) or uuid. Empty = board/list. */ issue: string } /** Body of `POST …/issues`. */ export interface NewIssueCmd { title: string description?: string | null content?: string priority?: IssuePriority due_at?: string | null milestone_id?: string | null assignee_ids?: number[] label_ids?: string[] /** Draft upload ids from `POST /issues/attachments` to link to the new issue. */ attachment_ids?: string[] } /** * Body of `PATCH …/issues/{id}`. Three-state fields: absent = unchanged, * `null` = cleared, value = set — so the caller must not send `undefined` * for a field it wants cleared. */ export interface IssuePatchCmd { title?: string description?: string | null content?: string priority?: IssuePriority due_at?: string | null milestone_id?: string | null assignee_ids?: number[] label_ids?: string[] }