feat: add unified New Task button with full detail view creation#2350
feat: add unified New Task button with full detail view creation#2350maggch97 wants to merge 9 commits intogo-vikunja:mainfrom
Conversation
objectToCamelCase was recursing into Date objects (typeof Date === 'object'), destroying them into empty objects. Add the same Date skip guard that objectToSnakeCase already has, plus a getTime duck type check for Vue reactive proxied Dates. Also use the null-safe parseDate helper for created/updated fields in TaskService.processModel, matching how all other date fields are already handled. The server sets these fields on creation anyway. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a 'New Task' button in the project header (ProjectWrapper) that appears consistently across List, Table, Kanban, and Gantt views. Clicking navigates to a task detail view in 'create mode', providing an Azure DevOps-like experience where the full task form is available before submission. Create mode behavior: - Route: /projects/:projectId/tasks/new - Shows 'New' as task identifier, editable title - Full rich text description editor (TipTap), no auto-save to API - Priority, dates, color, percent done, reminders, repeat interval all editable locally without triggering API calls - Assignee selection stored locally, assigned after creation - Save button creates the task and redirects to real detail view - Features requiring real task ID hidden: labels, attachments, comments, reactions, related tasks, move project, subscriptions Technical approach: - provide/inject for isNewTask flag (avoids prop drilling) - saveTask() is a no-op in create mode (v-model keeps state) - createNewTask() reads directly from task ref (avoids klona Date serialization issues) - Description component injects isNewTask to skip API saves - EditAssignees injects isNewTask to skip assignee API calls - Heading component accepts isNewTask prop for identifier display Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests cover: - New Task button visibility across list, table, kanban views - Button hidden for read-only projects - Navigation to new task page - New task identifier shows 'New' - Project name displayed - Save button visible, Done button hidden - Comments section hidden - Task creation with title only - Task creation with priority - Task creation with due date Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Future improvementsThe following features are currently hidden in create mode because their APIs require a real task ID. They can be added in follow-up PRs using the same pattern as assignees (store locally, call API after creation):
|
Preview DeploymentPreview deployments for this PR are available at:
The preview environment will start automatically on first visit. Subsequent pushes to this PR will update the Run locally with Dockerdocker pull ghcr.io/go-vikunja/vikunja:pr-2350
docker run -p 3456:3456 ghcr.io/go-vikunja/vikunja:pr-2350Last updated for commit c04fc8f |
Consistent with Description and EditAssignees which already use
inject('isNewTask'). Removes the last prop-drilled isNewTask.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove unnecessary getTime duck type check, keep only instanceof Date to match objectToSnakeCase's style. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use v-if='!isNewTask' to hide task-specific buttons (done, favorite, subscription, labels, attachments, related tasks, move, delete) instead of duplicating the entire button panel. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n createNewTask These were copied from saveTask but serve no purpose for new tasks: - endDate fallback to dueDate is an edit-time convenience, not needed at creation - hexColor was pointlessly extracted to a separate variable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description component uses a 5-second delay before syncing to the parent via emit. In new task mode there's no API call, so sync immediately on every change. This ensures task.value.description is up-to-date when the user clicks Save without first clicking the editor's save button. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verifies that typing in the description editor and directly clicking Save (without the editor's own save button) correctly persists the description to the created task. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kolaente
left a comment
There was a problem hiding this comment.
Thanks!
I'm unsure if this is the best way to do this, especially since the task detail view is getting cluttered with these many new checks. What do you think about creating just a simple form that allows to set a title, description, maybe color and dates? Then redirect to the task's detail view, allowing to edit the task with all related properties.
In either case, it should auto focus the title input and be shown in a modal instead of this full view.
I use Azure DevOps a lot and it has a same page layout for create and edit, so I prefer this instead of a new simple dialog. I believe different users may have different requirements for task creation, some users may want to set labels, some users may want to set assignees and some others may want to upload some files. So finally, we may want the new task page to be consistent with the details page. |
|
Updated per review feedback:
|
Summary
Following the discussion in #2325, this adds a unified "New Task" button across all project views (List, Table, Kanban, Gantt) with a full task detail creation experience.
Instead of a quick-add text input, clicking "New Task" opens the full task detail view in create mode — similar to Azure DevOps where you fill in all fields before saving.
Changes
New Task Button
ProjectWrapper.vue(right side of header, after filter/columns buttons)/projects/:projectId/tasks/newCreate Mode (
TaskDetailView)Technical Approach
provide/injectforisNewTaskflag (avoids prop drilling into Description, EditAssignees)saveTask()is a no-op in create mode — Vuev-modelkeeps local state in synccreateNewTask()reads directly fromtask.value(avoidsklonaDate serialization issues)Bug Fixes (independent, first commit)
objectToCamelCasewas recursing intoDateobjects, destroying them into{}. Added the same Date skip guard thatobjectToSnakeCasealready has.TaskService.processModelusednew Date(null).toISOString()forcreated/updatedwhich throws. Now uses the null-safeparseDatehelper like all other date fields.E2E Tests
13 Playwright tests covering:
Known Limitations
Closes #2325