This commit is contained in:
@@ -5,8 +5,8 @@ import {
|
|||||||
GripVertical, Inbox, ListChecks, ListTodo, Menu, Pencil, Plus, Search,
|
GripVertical, Inbox, ListChecks, ListTodo, Menu, Pencil, Plus, Search,
|
||||||
Settings, Trash2, X, Repeat2,
|
Settings, Trash2, X, Repeat2,
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import { buildTaskRrule, filterTasks, fromDateTimeLocal, groupTaskTree, moveItemWithinScope, parseTaskRrule, renderMarkdown, toDateTimeLocal, type TaskRepeatConfig } from './lib/task-utils'
|
import { buildTaskRrule, defaultTaskDueAt, filterTasks, fromDateTimeLocal, groupTaskTree, moveItemWithinScope, parseTaskRrule, renderMarkdown, toDateTimeLocal, type TaskRepeatConfig } from './lib/task-utils'
|
||||||
import { defaultView, isTaskView, nextTotalAfterLocalTaskAdd, quickTaskFields, shouldToggleRowSwipe, writeCountdownCache } from './lib/mvp-utils'
|
import { defaultView, isTaskView, nextTotalAfterLocalTaskAdd, shouldToggleRowSwipe, writeCountdownCache } from './lib/mvp-utils'
|
||||||
import { csrfHeader } from './lib/csrf'
|
import { csrfHeader } from './lib/csrf'
|
||||||
import MvpPanel from './MvpPanel.vue'
|
import MvpPanel from './MvpPanel.vue'
|
||||||
import CountdownPanel from './CountdownPanel.vue'
|
import CountdownPanel from './CountdownPanel.vue'
|
||||||
@@ -80,7 +80,7 @@ function openTaskCompose() {
|
|||||||
const inboxId = lists.value.find((item) => item.is_inbox)?.id || activeList.value
|
const inboxId = lists.value.find((item) => item.is_inbox)?.id || activeList.value
|
||||||
composeTitle.value = ''
|
composeTitle.value = ''
|
||||||
composeListId.value = activeView.value === 'tasks' && activeList.value ? activeList.value : inboxId
|
composeListId.value = activeView.value === 'tasks' && activeList.value ? activeList.value : inboxId
|
||||||
composeDueAt.value = activeView.value === 'today' ? toDateTimeLocal(quickTaskFields('today', activeList.value, inboxId).due_at ?? null) : ''
|
composeDueAt.value = defaultTaskDueAt()
|
||||||
composePriority.value = 0
|
composePriority.value = 0
|
||||||
composeDescription.value = ''
|
composeDescription.value = ''
|
||||||
composeRepeat.value = 'none'
|
composeRepeat.value = 'none'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { buildTaskRrule, filterTasks, groupTaskTree, moveItemWithinScope, parseTaskRrule, renderMarkdown, toDateTimeLocal } from './task-utils'
|
import { buildTaskRrule, defaultTaskDueAt, filterTasks, groupTaskTree, moveItemWithinScope, parseTaskRrule, renderMarkdown, toDateTimeLocal } from './task-utils'
|
||||||
|
|
||||||
type SearchTask = {
|
type SearchTask = {
|
||||||
id: string
|
id: string
|
||||||
@@ -63,6 +63,11 @@ describe('task utilities', () => {
|
|||||||
expect(filterTasks(searchable, '工作').map((task) => task.id)).toEqual(['4'])
|
expect(filterTasks(searchable, '工作').map((task) => task.id)).toEqual(['4'])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('defaults new tasks to today at noon in local time', () => {
|
||||||
|
const due = defaultTaskDueAt(new Date(2026, 8, 8, 21, 30))
|
||||||
|
expect(due).toBe('2026-09-08T12:00')
|
||||||
|
})
|
||||||
|
|
||||||
it('formats API dates in local wall-clock time', () => {
|
it('formats API dates in local wall-clock time', () => {
|
||||||
const original = process.env.TZ
|
const original = process.env.TZ
|
||||||
process.env.TZ = 'Asia/Shanghai'
|
process.env.TZ = 'Asia/Shanghai'
|
||||||
|
|||||||
@@ -144,6 +144,13 @@ export function parseTaskRrule(rrule = ''): TaskRepeatConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function defaultTaskDueAt(now = new Date()) {
|
||||||
|
const year = now.getFullYear()
|
||||||
|
const month = `${now.getMonth() + 1}`.padStart(2, '0')
|
||||||
|
const day = `${now.getDate()}`.padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}T12:00`
|
||||||
|
}
|
||||||
|
|
||||||
export function toDateTimeLocal(value: string | null | undefined) {
|
export function toDateTimeLocal(value: string | null | undefined) {
|
||||||
if (!value) return ''
|
if (!value) return ''
|
||||||
const date = new Date(value)
|
const date = new Date(value)
|
||||||
|
|||||||
@@ -183,6 +183,11 @@ describe('mobile touch targets', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('unified floating add interaction', () => {
|
describe('unified floating add interaction', () => {
|
||||||
|
it('defaults every new-task composer to today', () => {
|
||||||
|
expect(app).toContain('composeDueAt.value = defaultTaskDueAt()')
|
||||||
|
expect(app).not.toContain("activeView.value === 'today' ? toDateTimeLocal(quickTaskFields")
|
||||||
|
})
|
||||||
|
|
||||||
it('lets task create and detail forms configure a repeat rule', () => {
|
it('lets task create and detail forms configure a repeat rule', () => {
|
||||||
expect(app).toContain('const composeRepeat = ref')
|
expect(app).toContain('const composeRepeat = ref')
|
||||||
expect(app).toContain('const selectedTaskRepeat = ref')
|
expect(app).toContain('const selectedTaskRepeat = ref')
|
||||||
|
|||||||
Reference in New Issue
Block a user