Syncs the sort choice to a ?sort=field:order URL parameter so it
survives page refreshes and can be shared. The default position sort
is omitted from the URL to keep links clean.
Previously only the "To-Do" default bucket was deleted, leaving "Doing"
and "Done" as duplicates alongside migration-provided buckets. Now all
default-created buckets are removed when migration data already provides
bucket assignments for all tasks.
Add comprehensive tests for the WeKan conversion function including
edge cases (empty board, orphan cards, color mapping, multiple
checklists, unsupported fields) and a realistic JSON fixture file.
Add a file-based migration importer that reads WeKan board JSON exports
and creates Vikunja projects with kanban buckets, tasks, labels,
checklists, and comments.
WeKan lists become kanban buckets. Checklists are converted to HTML
task lists in the description. Card descriptions and comments are
converted from markdown to HTML using goldmark. Label colors are
mapped from WeKan's CSS color names to their actual hex values.
Resolves#2490. Users with team access on a parent project were not seeing
subtask relations for tasks in child projects because getUserProjectsStatement
does not walk the project hierarchy. The fix wraps the base query in a
recursive CTE that traverses child projects via parent_project_id.
When closing a task modal opened from the Gantt view, the date range
query parameters were lost because closeModal() reconstructed the
route with only projectId and viewId. Now preserves query parameters
from the backdrop view.
Replace static initialDateRange snapshot with reactive filters.value
references inside the computed flatPickerConfig. This ensures the
Flatpickr defaultDate always reflects the current user-selected range
instead of the mount-time values.
Ref #2462
With truncateAll wiping all tables, the test user has no projects,
so ShowTasks never renders and tasksLoaded stays false — meaning
ImportHint (which is gated on tasksLoaded) never appears. Seed a
project with default views so the empty-state hint is visible.
Add isFilteredView parameter to shouldShowTaskInListView() that skips
the parent-hiding logic when viewing tasks through a saved filter.
This ensures all filter-matching tasks are shown.
Ref: #2494
Sets position: relative and z-index: 0 on .gantt-chart-container to
create a new stacking context. This ensures z-index values inside the
Gantt chart (e.g. the sticky timeline header) cannot compete with the
Flatpickr popup that renders at the body level.
Ref #2337
Adds min-inline-size: 100% to .gantt-container so the scrollable area
never appears narrower than the card width, even with short date ranges.
Ref #2337
Moves the drag handle inside the color-bubble-wrapper so both elements
share the same positioned container, eliminating the absolute positioning
mismatch that caused the overlap. Fixes#2493.
Verifies that tasks from read-only shared projects have disabled
checkboxes on the overview page, while tasks from owned projects
remain interactive.
Refs #2399
The Overview's ShowTasks component was not passing the canMarkAsDone prop
to SingleTaskInProject, which defaults to true. This caused read-only tasks
to show an interactive checkbox even though the user doesn't have write
permission.
Use the project's maxPermission from the project store to determine if the
user can mark the task as done. Also fix the disabled condition to use OR
logic so the checkbox is disabled when ANY condition applies: archived,
disabled, or when the user lacks write permission.
Fixes#2399
Add a single retry with a 1-second delay in the 401 interceptor's
doRefresh() before giving up on token renewal. This handles transient
failures like brief network blips or server restarts without immediately
logging the user out.
Also log refresh failures via console.warn so the reason is visible
in browser DevTools for easier diagnosis.
Ref: #2391
When window.API_URL lacks a trailing slash, axios resolves relative URLs
by stripping path segments, causing the refresh request to hit a different
path than the cookie's Path attribute. The browser then omits the HttpOnly
refresh cookie, silently breaking token renewal and logging users out
after the short JWT TTL expires.
Extract a getApiBaseUrl() helper that ensures baseURL always ends with
'/' so relative URL resolution preserves the full path, matching the
cookie scope.
Ref: #2391
GetMailDomain called log.Warningf which panics when the logger is not
initialized (e.g. in unit tests). Add log.IsInitialized() guard.
Also fix TestGetThreadID tests that hardcoded "vikunja" as the expected
fallback domain - on CI the os.Hostname() fallback produces a different
value. Tests now dynamically compute the expected domain.