Skip to content

feat: add unified New Task button with full detail view creation#2350

Open
maggch97 wants to merge 9 commits intogo-vikunja:mainfrom
maggch97:feat/new-task-entry
Open

feat: add unified New Task button with full detail view creation#2350
maggch97 wants to merge 9 commits intogo-vikunja:mainfrom
maggch97:feat/new-task-entry

Conversation

@maggch97
Copy link
Contributor

@maggch97 maggch97 commented Mar 4, 2026

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

  • Added in ProjectWrapper.vue (right side of header, after filter/columns buttons)
  • Visible when user has write permission and project is not archived
  • Route: /projects/:projectId/tasks/new

Create Mode (TaskDetailView)

  • Shows "New" as the task identifier
  • Editable title (inline contenteditable, same as existing tasks)
  • Full TipTap rich text editor for description
  • Priority, dates, color, percent done, reminders, repeat interval — all editable locally, no API calls until Save
  • Assignees — selected locally, assigned via API after creation
  • Save button creates the task and redirects to the real task detail URL
  • Hidden until after creation: labels, attachments, comments, reactions, related tasks, move project, subscriptions, favorites

Technical Approach

  • provide/inject for isNewTask flag (avoids prop drilling into Description, EditAssignees)
  • saveTask() is a no-op in create mode — Vue v-model keeps local state in sync
  • createNewTask() reads directly from task.value (avoids klona Date serialization issues)

Bug Fixes (independent, first commit)

  • objectToCamelCase was recursing into Date objects, destroying them into {}. Added the same Date skip guard that objectToSnakeCase already has.
  • TaskService.processModel used new Date(null).toISOString() for created/updated which throws. Now uses the null-safe parseDate helper like all other date fields.

E2E Tests

13 Playwright tests covering:

  • Button visibility across views and read-only projects
  • Navigation to new task page
  • UI elements (identifier, project name, Save/Done buttons, comments)
  • Task creation with title, priority, and due date

Known Limitations

  • Attachments are not available in create mode (API requires a real task ID). This also means images cannot be inserted in the description during creation.
  • Labels require a real task ID for the label-task association API, so they are hidden in create mode.
  • These features become available immediately after clicking Save and being redirected to the real task detail view.

Closes #2325

maggch97 and others added 3 commits March 4, 2026 12:02
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>
@maggch97
Copy link
Contributor Author

maggch97 commented Mar 4, 2026

Future improvements

The 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):

  • LabelsEditLabels already has partial taskId === 0 handling. Need to fix createAndAddLabel to not early-return when taskId === 0, enable the labels section in the template, and call taskStore.addLabel() in createNewTask() after creation.
  • Attachments — Would need to buffer selected files locally, upload via PUT /tasks/{taskId}/attachments after creation. This would also enable image insertion in the description editor during creation.
  • Related tasks — Similar pattern: store relation definitions locally, call the relation API after creation.

@github-actions
Copy link

github-actions bot commented Mar 4, 2026

Preview Deployment

Preview deployments for this PR are available at:

URL Tag Commit
https://pr-2350.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:pr-2350 latest
https://sha-c04fc8f1855b7dbeea5b039896dde642119af6ee.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-c04fc8f1855b7dbeea5b039896dde642119af6ee c04fc8f
https://sha-ebea77dbab4c3b1bdb8b029c2d24518376cc7c99.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-ebea77dbab4c3b1bdb8b029c2d24518376cc7c99 ebea77d
https://sha-e9e40108d1f77e5a291cb692822adf56826756ee.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-e9e40108d1f77e5a291cb692822adf56826756ee e9e4010
https://sha-eea04715f367b774762030a4f36efe09b2f12782.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-eea04715f367b774762030a4f36efe09b2f12782 eea0471
https://sha-77847730a479cc94c2e6984c72c007dec7ccb582.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-77847730a479cc94c2e6984c72c007dec7ccb582 7784773
https://sha-fcfc90a7e34cc65ee982e50a826870936d574efd.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-fcfc90a7e34cc65ee982e50a826870936d574efd fcfc90a
https://sha-7c939a92187907110f957443866d2d6490c2f3f3.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-7c939a92187907110f957443866d2d6490c2f3f3 7c939a9

The preview environment will start automatically on first visit. Subsequent pushes to this PR will update the pr-2350 image — the preview picks up the new version on restart. The per-commit URLs point to a specific version and will not change.

Run locally with Docker
docker pull ghcr.io/go-vikunja/vikunja:pr-2350
docker run -p 3456:3456 ghcr.io/go-vikunja/vikunja:pr-2350

Last updated for commit c04fc8f

maggch97 and others added 6 commits March 4, 2026 16:39
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>
Copy link
Member

@kolaente kolaente left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@maggch97
Copy link
Contributor Author

maggch97 commented Mar 9, 2026

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.

@maggch97
Copy link
Contributor Author

maggch97 commented Mar 9, 2026

Updated per review feedback:

  • New Task button now only appears in Table view (List/Kanban/Gantt have their own creation UIs)
  • Opens as a modal instead of a full page view
  • Auto-focuses the title on open
  • E2E tests updated accordingly, all 14 passing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants