Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .mockapi/behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Require the visible deck and next parent, reject duplicate visible titles in the

Status: inferred

Require the visible deck and return visible note list items for that deck. Support `sortField=title|updated` and `sortDirection=asc|desc`.
Require the visible deck and return visible note list items for that deck. Support `sortField=dueAt|progress|title|updatedAt` and `sortDirection=asc|desc`.

## operation:createNote

Expand Down
28 changes: 28 additions & 0 deletions api/mock-server/src/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,34 @@ describe('mock api app', () => {
)
})

it('sorts deck notes by due date', async () => {
const app = await newMockApiApp()

const response = await app.fetch(
new Request('http://localhost/api/v1/decks/world-history/notes?sortField=dueAt&sortDirection=desc'),
)

expect(response.status).toBe(200)
await expect(json<Array<{ id: string }>>(response)).resolves.toEqual([
expect.objectContaining({ id: 'postwar-institutions' }),
expect.objectContaining({ id: 'industrial-revolution-causes' }),
])
})

it('sorts deck notes by progress', async () => {
const app = await newMockApiApp()

const response = await app.fetch(
new Request('http://localhost/api/v1/decks/world-history/notes?sortField=progress&sortDirection=asc'),
)

expect(response.status).toBe(200)
await expect(json<Array<{ id: string }>>(response)).resolves.toEqual([
expect.objectContaining({ id: 'postwar-institutions' }),
expect.objectContaining({ id: 'industrial-revolution-causes' }),
])
})

it('exposes admin state reset and inspection endpoints', async () => {
const app = await newMockApiApp()

Expand Down
4 changes: 2 additions & 2 deletions api/mock-server/src/features/decks/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { visible } from '../../lib/softDelete.ts'
import { byStringField } from '../../lib/sort.ts'

type SortDirection = 'asc' | 'desc'
type DeckSortField = 'dueToday' | 'title' | 'updated'
type DeckSortField = 'dueToday' | 'title' | 'updatedAt'

const sortDecks = (
decks: DeckRecord[],
Expand All @@ -23,7 +23,7 @@ const sortDecks = (
return (left.dueToday - right.dueToday) * direction
}

if (sortField === 'updated') {
if (sortField === 'updatedAt') {
return left.updatedAt.localeCompare(right.updatedAt) * direction
}

Expand Down
4 changes: 3 additions & 1 deletion api/mock-server/src/features/decks/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ export class DeckService {
return {
sortDirection: query.sortDirection === 'desc' ? 'desc' : 'asc',
sortField:
query.sortField === 'dueToday' || query.sortField === 'title' || query.sortField === 'updated'
query.sortField === 'dueToday' ||
query.sortField === 'title' ||
query.sortField === 'updatedAt'
? query.sortField
: undefined,
} as const
Expand Down
4 changes: 2 additions & 2 deletions api/mock-server/src/features/folders/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { visible } from '../../lib/softDelete.ts'
import { byStringField } from '../../lib/sort.ts'

type SortDirection = 'asc' | 'desc'
type FolderSortField = 'title' | 'updated'
type FolderSortField = 'title' | 'updatedAt'

const sortFolders = (
folders: FolderRecord[],
Expand All @@ -19,7 +19,7 @@ const sortFolders = (
const direction = sortDirection === 'desc' ? -1 : 1

return [...folders].sort((left, right) => {
if (sortField === 'updated') {
if (sortField === 'updatedAt') {
return left.updatedAt.localeCompare(right.updatedAt) * direction
}

Expand Down
3 changes: 2 additions & 1 deletion api/mock-server/src/features/folders/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ export class FolderService {
private parseSortQuery(query: { sortField?: string; sortDirection?: string } = {}) {
return {
sortDirection: query.sortDirection === 'desc' ? 'desc' : 'asc',
sortField: query.sortField === 'title' || query.sortField === 'updated' ? query.sortField : undefined,
sortField:
query.sortField === 'title' || query.sortField === 'updatedAt' ? query.sortField : undefined,
} as const
}

Expand Down
50 changes: 50 additions & 0 deletions api/mock-server/src/features/notes/repository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, expect, it } from 'vitest'

import { newMemoryMockStateStore } from '../../lib/stateStore.ts'
import { NotesRepository } from './repository.ts'

describe('NotesRepository', () => {
it('sorts deck notes by due date', async () => {
const notes = new NotesRepository(await newMemoryMockStateStore())

expect(
notes
.listByDeck('world-history', {
sortDirection: 'asc',
sortField: 'dueAt',
})
.map((note) => note.id),
).toEqual(['industrial-revolution-causes', 'postwar-institutions'])

expect(
notes
.listByDeck('world-history', {
sortDirection: 'desc',
sortField: 'dueAt',
})
.map((note) => note.id),
).toEqual(['postwar-institutions', 'industrial-revolution-causes'])
})

it('sorts deck notes by progress', async () => {
const notes = new NotesRepository(await newMemoryMockStateStore())

expect(
notes
.listByDeck('world-history', {
sortDirection: 'asc',
sortField: 'progress',
})
.map((note) => note.id),
).toEqual(['postwar-institutions', 'industrial-revolution-causes'])

expect(
notes
.listByDeck('world-history', {
sortDirection: 'desc',
sortField: 'progress',
})
.map((note) => note.id),
).toEqual(['industrial-revolution-causes', 'postwar-institutions'])
})
})
12 changes: 10 additions & 2 deletions api/mock-server/src/features/notes/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { visible } from '../../lib/softDelete.ts'
import { byStringField } from '../../lib/sort.ts'

type SortDirection = 'asc' | 'desc'
type NoteSortField = 'title' | 'updated'
type NoteSortField = 'dueAt' | 'progress' | 'title' | 'updatedAt'

const sortNotes = (
notes: NoteDetailRecord[],
Expand All @@ -19,7 +19,15 @@ const sortNotes = (
const direction = sortDirection === 'desc' ? -1 : 1

return [...notes].sort((left, right) => {
if (sortField === 'updated') {
if (sortField === 'dueAt') {
return (new Date(left.dueAt).getTime() - new Date(right.dueAt).getTime()) * direction
}

if (sortField === 'progress') {
return (left.progress - right.progress) * direction
}

if (sortField === 'updatedAt') {
return left.updatedAt.localeCompare(right.updatedAt) * direction
}

Expand Down
8 changes: 7 additions & 1 deletion api/mock-server/src/features/notes/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ export class NotesService {
listNotesByDeck(deckId: string, query?: { sortField?: string; sortDirection?: string }): NoteListItem[] {
const deck = this.decks.require(deckId)
const sortQuery = query ?? {}
const sortField = sortQuery.sortField === 'title' || sortQuery.sortField === 'updated' ? sortQuery.sortField : undefined
const sortField =
sortQuery.sortField === 'dueAt' ||
sortQuery.sortField === 'progress' ||
sortQuery.sortField === 'title' ||
sortQuery.sortField === 'updatedAt'
? sortQuery.sortField
: undefined
const sortDirection = sortQuery.sortDirection === 'desc' ? 'desc' : 'asc'

return this.notes.listByDeck(deck.id ?? '', { sortField, sortDirection }).map(toNoteListItem)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions api/mock-server/src/generated/clear-web-api/contract/zod.gen.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions api/openapi/shared/components.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -197,21 +197,23 @@ components:
enum:
- dueToday
- title
- updated
- updatedAt
example: title

FolderSortField:
type: string
enum:
- title
- updated
- updatedAt
example: title

NoteSortField:
type: string
enum:
- dueAt
- progress
- title
- updated
- updatedAt
example: title

SortDirection:
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ export const ar = {
},
labels: {
deleted: 'حذف {{value}}',
due: 'مستحق: {{value}}',
reviewed: 'تمت المراجعة: {{value}}',
updated: 'تم التحديث {{value}}',
updatedUppercase: 'تم التحديث {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/bg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const bg = {
},
labels: {
deleted: 'Изтрито {{value}}',
due: 'Срок: {{value}}',
reviewed: 'Преговорено: {{value}}',
updated: 'Обновено {{value}}',
updatedUppercase: 'ОБНОВЕНО {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/bs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export const bs = {
},
labels: {
deleted: 'Izbrisano {{value}}',
due: 'Rok: {{value}}',
reviewed: 'Ponovljeno: {{value}}',
updated: 'Ažurirano {{value}}',
updatedUppercase: 'AŽURIRANO {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export const ca = {
},
labels: {
deleted: 'Suprimit {{value}}',
due: 'Venciment: {{value}}',
reviewed: 'Repassat: {{value}}',
updated: 'Actualitzat {{value}}',
updatedUppercase: 'ACTUALITZAT {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export const cs = {
},
labels: {
deleted: 'Smazáno {{value}}',
due: 'Termín: {{value}}',
reviewed: 'Opakováno: {{value}}',
updated: 'Aktualizováno {{value}}',
updatedUppercase: 'AKTUALIZOVÁNO {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const da = {
},
labels: {
deleted: 'Slettet {{value}}',
due: 'Forfalder: {{value}}',
reviewed: 'Gentaget: {{value}}',
updated: 'Opdateret {{value}}',
updatedUppercase: 'OPDATERET {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const de = {
},
labels: {
deleted: 'Gelöscht {{value}}',
due: 'Fällig: {{value}}',
reviewed: 'Wiederholt: {{value}}',
updated: 'Aktualisiert {{value}}',
updatedUppercase: 'AKTUALISIERT {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const el = {
},
labels: {
deleted: 'Διαγράφηκε {{value}}',
due: 'Προθεσμία: {{value}}',
reviewed: 'Επαναλήφθηκε: {{value}}',
updated: 'Ενημερώθηκε {{value}}',
updatedUppercase: 'ΕΝΗΜΕΡΩΘΗΚΕ {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const enUS = {
},
labels: {
deleted: 'Deleted {{value}}',
due: 'Due: {{value}}',
reviewed: 'Reviewed: {{value}}',
updated: 'Updated {{value}}',
updatedUppercase: 'UPDATED {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const es = {
},
labels: {
deleted: 'Eliminado {{value}}',
due: 'Vence: {{value}}',
reviewed: 'Repasado: {{value}}',
updated: 'Actualizado {{value}}',
updatedUppercase: 'ACTUALIZADO {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/et.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const et = {
},
labels: {
deleted: 'Kustutatud {{value}}',
due: 'Tähtaeg: {{value}}',
reviewed: 'Korratud: {{value}}',
updated: 'Uuendatud {{value}}',
updatedUppercase: 'UUENDATUD {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const fa = {
},
labels: {
deleted: 'حذف‌شده {{value}}',
due: 'موعد: {{value}}',
reviewed: 'مرور شد: {{value}}',
updated: 'به‌روزرسانی‌شده {{value}}',
updatedUppercase: 'به‌روزرسانی‌شده {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/fi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const fi = {
},
labels: {
deleted: 'Poistettu {{value}}',
due: 'Erääntyy: {{value}}',
reviewed: 'Kerrattu: {{value}}',
updated: 'Päivitetty {{value}}',
updatedUppercase: 'PÄIVITETTY {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export const fr = {
},
labels: {
deleted: 'Supprimé {{value}}',
due: 'À réviser : {{value}}',
reviewed: 'Révisé : {{value}}',
updated: 'Mis à jour {{value}}',
updatedUppercase: 'MIS À JOUR {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/he.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export const he = {
},
labels: {
deleted: 'נמחק {{value}}',
due: 'מועד: {{value}}',
reviewed: 'נסקר: {{value}}',
updated: 'עודכן {{value}}',
updatedUppercase: 'עודכן {{value}}',
Expand Down
1 change: 0 additions & 1 deletion ui/src/core/i18n/resources/hr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export const hr = {
},
labels: {
deleted: 'Izbrisano {{value}}',
due: 'Rok: {{value}}',
reviewed: 'Ponovljeno: {{value}}',
updated: 'Ažurirano {{value}}',
updatedUppercase: 'AŽURIRANO {{value}}',
Expand Down
Loading