[verified] redesign trash with deadline groups
ci / gitleaks (push) Successful in 11s
ci / docker (push) Successful in 8m0s

This commit is contained in:
2026-09-21 09:00:07 +08:00
parent c7bb9742f1
commit 740eae8a59
11 changed files with 234 additions and 55 deletions
+14 -13
View File
@@ -14,7 +14,7 @@ const appSheet = readFileSync('src/components/AppSheet.vue', 'utf8')
describe('unified task due display', () => {
it('uses the shared display for overdue and ordinary parent task rows', () => {
expect(app).toContain("import TaskDueDisplay from './components/TaskDueDisplay.vue'")
expect(app.match(/<TaskDueDisplay/g)).toHaveLength(2)
expect(app.match(/<TaskDueDisplay/g)).toHaveLength(3)
expect(app).toContain(':due-at="node.task.due_at"')
expect(app).not.toContain(':due-at="subtask.due_at"')
expect(app).not.toContain('formatDue(')
@@ -31,10 +31,10 @@ describe('unified task due display', () => {
})
it('places every visible-list due display in a right tail before stable actions', () => {
expect(app.match(/<span v-if="[^\"]+\.due_at" class="task-tail"><TaskDueDisplay/g)).toHaveLength(2)
expect(app.match(/<span v-if="[^\"]+\.due_at" class="task-tail"><TaskDueDisplay/g)).toHaveLength(3)
expect(app).not.toContain('class="meta"><TaskDueDisplay')
expect(app).toContain('</div><span v-if="node.task.due_at" class="task-tail"><TaskDueDisplay')
expect(app).toContain('</span><span v-if="activeView===\'trash\'" class="task-actions">')
expect(app).toContain('<span class="task-actions"><button class="restore" @click.stop="restoreTask(node.task)">')
expect(app).not.toContain('restoreTask(subtask)')
expect(app).not.toContain('purgeTask(subtask)')
expect(app).not.toContain('task-detail-trigger')
@@ -160,7 +160,7 @@ describe('approved Settings 01 paper ledger', () => {
it('moves Settings identity into the body and suppresses the duplicate shell title', () => {
expect(app).not.toContain("'settings-main':activeView==='settings'")
expect(app).toContain(":class=\"{'settings-topbar':activeView==='settings'}\"")
expect(app).toContain("v-if=\"!['today','tasks','upcoming','habits','settings'].includes(activeView)\" class=\"topbar-title\"")
expect(app).toContain("v-if=\"!['today','tasks','upcoming','trash','habits','settings'].includes(activeView)\" class=\"topbar-title\"")
expect(app).not.toContain('v-if="activeView===\'settings\'" class="icon topbar-refresh settings-refresh"')
expect(app).not.toContain('aria-label="刷新当前页面"')
expect(mvpPanel).toContain('<header class="settings-heading"><h1>设置</h1><p>管理数据、账户与登录设备</p></header>')
@@ -317,22 +317,23 @@ describe('solid cream material system', () => {
describe('approved UI detail direction', () => {
it('opens ordinary and overdue task details from the task body while preserving Trash actions', () => {
const ordinaryStart = app.indexOf('<section :id="activeView===\'today\' ? \'today-tasks\' : undefined"')
const ordinaryStart = app.indexOf('<section v-else :id="activeView===\'today\' ? \'today-tasks\' : undefined"')
const ordinaryRows = app.slice(ordinaryStart, app.indexOf('</section>', ordinaryStart))
expect(ordinaryRows).toContain("selectTaskUnlessSwiped(node.task)")
expect(ordinaryRows).not.toContain('task-detail-trigger')
expect(ordinaryRows).not.toContain('selectTask(subtask)')
expect(ordinaryRows).not.toContain('aria-label="删除任务"')
expect(ordinaryRows).toContain('v-if="activeView===\'trash\'" class="task-actions"')
expect(ordinaryRows).toContain('restoreTask(node.task)')
expect(ordinaryRows).toContain('purgeTask(node.task)')
const trashRows = app.slice(app.indexOf('class="trash-groups"'), ordinaryStart)
expect(trashRows).toContain('class="task-actions"')
expect(trashRows).toContain('restoreTask(node.task)')
expect(trashRows).toContain('purgeTask(node.task)')
const overdue = app.slice(app.indexOf('<section v-if="overdueTaskTree.length"'), app.indexOf('id="today-tasks-heading"'))
expect(overdue).toContain('selectTaskUnlessSwiped(node.task)')
expect(overdue).not.toContain('aria-label="打开任务详情"')
})
it('keeps the due tail as the final parent-row control and opens details from the task body', () => {
expect(app).toContain('@click="activeView===\'trash\'?undefined:selectTaskUnlessSwiped(node.task)"')
expect(app).toContain('@click="selectTaskUnlessSwiped(node.task)"')
expect(app).toContain('<span v-if="node.task.due_at" class="task-tail">')
expect(app).not.toContain('task-detail-trigger')
expect(css).not.toContain('.task-detail-trigger')
@@ -798,7 +799,7 @@ describe('task and habit row decoration', () => {
it('shows task drag handles only in an explicit available reorder mode', () => {
expect(app).toContain('const taskReorderMode = ref(false)')
expect(app).toContain("const taskReorderAvailable = computed(() => activeView.value === 'tasks' && totalPages.value === 1 && taskTree.value.length > 1)")
expect(app).toContain('class="soft-button reorder-mode-toggle task-reorder-toggle"')
expect(app).toContain('class="list-section-action"')
expect(app).toContain("{{ taskReorderMode ? '完成' : '调整顺序' }}")
expect(app).toContain('v-if="taskReorderMode" class="drag-handle task-drag-handle"')
expect(app).toContain('if (!taskReorderAvailable.value) taskReorderMode.value = false')
@@ -835,7 +836,7 @@ describe('task and habit row decoration', () => {
})
it('exposes complete titles on every ellipsized visible task title node', () => {
expect(app.match(/<strong :title="node\.task\.title">\{\{node\.task\.title\}\}<\/strong>/g)).toHaveLength(2)
expect(app.match(/<strong :title="node\.task\.title">\{\{node\.task\.title\}\}<\/strong>/g)).toHaveLength(3)
expect(app).not.toContain('<strong :title="subtask.title">{{subtask.title}}</strong>')
expect(app).not.toContain('<strong>{{node.task.title}}</strong>')
})
@@ -901,7 +902,7 @@ describe('task and habit row decoration', () => {
expect(ordinaryRows).not.toContain('v-for="subtask in node.subtasks"')
expect(app).not.toContain('collapsedTaskIds')
expect(app).not.toContain('toggleTaskChildren')
expect(app.match(/<span v-if="node\.subtasks\.length" class="meta">/g)).toHaveLength(2)
expect(app.match(/<span v-if="node\.subtasks\.length" class="meta">/g)).toHaveLength(3)
expect(app).toContain('v-for="subtask in selectedTaskSubtasks"')
expect(app).toContain('class="subtask-detail"')
})
@@ -1135,7 +1136,7 @@ describe('task and habit row decoration', () => {
expect(mvpPanel).toContain("emit('summary', value)")
expect(app).toContain('taskComposeTitle')
expect(app).toContain('添加今天任务')
expect(app).toContain('v-if="activeView===\'trash\' || totalPages > 1 || totalTasks > 0"')
expect(app).toContain('<span class="trash-page-count">共 {{totalTasks}} 项</span>')
expect(mvpPanel).toContain('class="empty-panel today-empty-panel"')
expect(mvpPanel).toContain('添加习惯')
expect(css).toContain('.today-context{')