Add board and stack management for 0.3.0
Some checks are pending
Validate Decky / web-client (push) Waiting to run
Some checks are pending
Validate Decky / web-client (push) Waiting to run
This commit is contained in:
parent
dfb04462f3
commit
6a8c6a1eb6
16 changed files with 364 additions and 92 deletions
|
|
@ -23,6 +23,43 @@ describe('DeckApiClient', () => {
|
|||
expect(client.apiBaseUrl.toString()).toBe('https://cloud.example.test/apps/deck/api/v1.0/');
|
||||
});
|
||||
|
||||
it('creates, updates, and deletes boards with Deck-compatible payloads', async () => {
|
||||
const fetchImpl = vi.fn<FetchLike>().mockImplementation(async (input, init) => {
|
||||
if (String(input).endsWith('/boards') && !init?.method) return json([]);
|
||||
return init?.method === 'DELETE' ? new Response(null, { status: 204 }) : json({ id: 4, title: 'Projects', color: '0082C9' });
|
||||
});
|
||||
const client = await DeckApiClient.connect(options, fetchImpl);
|
||||
|
||||
await client.createBoard('Projects', '#0082c9');
|
||||
await client.updateBoard(4, 'Projects 2026', '46BA61');
|
||||
await client.deleteBoard(4);
|
||||
|
||||
expect(String(fetchImpl.mock.calls[1][0])).toMatch(/\/boards$/);
|
||||
expect(fetchImpl.mock.calls[1][1]?.method).toBe('POST');
|
||||
expect(JSON.parse(String(fetchImpl.mock.calls[1][1]?.body))).toEqual({ title: 'Projects', color: '0082C9' });
|
||||
expect(String(fetchImpl.mock.calls[2][0])).toMatch(/\/boards\/4$/);
|
||||
expect(JSON.parse(String(fetchImpl.mock.calls[2][1]?.body))).toEqual({ title: 'Projects 2026', color: '46BA61', archived: false });
|
||||
expect(fetchImpl.mock.calls[3][1]?.method).toBe('DELETE');
|
||||
});
|
||||
|
||||
it('creates, renames, and deletes stacks while preserving order', async () => {
|
||||
const fetchImpl = vi.fn<FetchLike>().mockImplementation(async (input, init) => {
|
||||
if (String(input).endsWith('/boards') && !init?.method) return json([]);
|
||||
return init?.method === 'DELETE' ? new Response(null, { status: 204 }) : json({ id: 9, boardId: 4, title: 'Next', order: 3, cards: [] });
|
||||
});
|
||||
const client = await DeckApiClient.connect(options, fetchImpl);
|
||||
|
||||
await client.createStack(4, 'Next', 3);
|
||||
await client.updateStack(4, 9, 'Later', 3);
|
||||
await client.deleteStack(4, 9);
|
||||
|
||||
expect(String(fetchImpl.mock.calls[1][0])).toMatch(/\/boards\/4\/stacks$/);
|
||||
expect(JSON.parse(String(fetchImpl.mock.calls[1][1]?.body))).toEqual({ title: 'Next', order: 3 });
|
||||
expect(String(fetchImpl.mock.calls[2][0])).toMatch(/\/boards\/4\/stacks\/9$/);
|
||||
expect(JSON.parse(String(fetchImpl.mock.calls[2][1]?.body))).toEqual({ title: 'Later', order: 3 });
|
||||
expect(fetchImpl.mock.calls[3][1]?.method).toBe('DELETE');
|
||||
});
|
||||
|
||||
it('preserves complete card fields and normalizes object owners', () => {
|
||||
const card: Card = {
|
||||
id: 1,
|
||||
|
|
|
|||
|
|
@ -106,10 +106,35 @@ export class DeckApiClient {
|
|||
return this.request<Board[]>('boards');
|
||||
}
|
||||
|
||||
createBoard(title: string, color: string): Promise<Board> {
|
||||
return this.request<Board>('boards', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ title, color: normalizeColor(color) })
|
||||
});
|
||||
}
|
||||
|
||||
updateBoard(boardId: number, title: string, color: string, archived = false): Promise<Board> {
|
||||
return this.request<Board>(`boards/${boardId}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ title, color: normalizeColor(color), archived })
|
||||
});
|
||||
}
|
||||
|
||||
deleteBoard(boardId: number): Promise<void> {
|
||||
return this.request<void>(`boards/${boardId}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
getStacks(boardId: number): Promise<Stack[]> {
|
||||
return this.request<Stack[]>(`boards/${boardId}/stacks`);
|
||||
}
|
||||
|
||||
createStack(boardId: number, title: string, order: number): Promise<Stack> {
|
||||
return this.request<Stack>(`boards/${boardId}/stacks`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ title, order })
|
||||
});
|
||||
}
|
||||
|
||||
updateStack(boardId: number, stackId: number, title: string, order: number): Promise<Stack> {
|
||||
return this.request<Stack>(`boards/${boardId}/stacks/${stackId}`, {
|
||||
method: 'PUT',
|
||||
|
|
@ -117,6 +142,10 @@ export class DeckApiClient {
|
|||
});
|
||||
}
|
||||
|
||||
deleteStack(boardId: number, stackId: number): Promise<void> {
|
||||
return this.request<void>(`boards/${boardId}/stacks/${stackId}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
async reorderStack(boardId: number, stackId: number, order: number): Promise<Stack[]> {
|
||||
const server = normalizeServerUrl(this.options.serverUrl);
|
||||
const url = new URL(`ocs/v2.php/apps/deck/api/v1.0/stacks/${stackId}/reorder`, server);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ export interface Board {
|
|||
archived?: boolean;
|
||||
lastModified?: number;
|
||||
deletedAt?: number;
|
||||
permissions?: {
|
||||
PERMISSION_READ?: boolean;
|
||||
PERMISSION_EDIT?: boolean;
|
||||
PERMISSION_MANAGE?: boolean;
|
||||
PERMISSION_SHARE?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Stack {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue