When later `urlToCheck` is restored in catch blocks, `origUrlToCheck`
will already be mutated.
Fixed by storing the original pathname as a string copy instead of
keeping a reference to the same URL object.
Split the monolithic parseTaskText.ts into a parseTaskText/ directory with
separate files for types, prefixes, prefix parsing, priority parsing, repeat
parsing, date parsing, and text cleanup. Moved parseDate.ts from helpers/time/
into the module since it's only consumed by the task text parser. Barrel export
in index.ts maintains backward compatibility — no consumer import changes needed.
https://claude.ai/code/session_01Aeo1ZunQUGKbWx2watMFdW
The kanban task move endpoint (POST /projects/:project/views/:view/
buckets/:bucket/tasks) is registered under the projects group as
views_buckets_tasks. Without this permission, the tasks preset cannot
move tasks between kanban buckets.
https://claude.ai/code/session_01QDWqXJmjriYoAcvMD43vmx
Add preset buttons (Read Only, Task Management, Project Management, Full
Access) to the API token creation form so users don't have to manually
select every individual permission.
https://claude.ai/code/session_01QDWqXJmjriYoAcvMD43vmx
When attachments are uploaded (either via file picker or pasting into
the description editor), update both the local task ref and the kanban
store so that the attachment list and kanban card icons stay in sync.
The attachment store was a global singleton shared between concurrent
TaskDetailView instances, causing a race condition when navigating
between tasks via related tasks from the Kanban view. Attachments
now live on the task ref like every other task field.
The Attachments component now reads attachments from its task prop
and emits update:attachments events instead of using the global
attachment store singleton.
When a user enables two factor authentication, all existing sessions are
now invalidated, requiring re-authentication. This prevents pre-existing
sessions from bypassing 2FA. The frontend now shows a notice explaining
the logout before the user confirms, and properly logs out after enabling.
Ref: GHSA-pgc7-cmvg-mvp4
The `simple` prop was introduced to hide some menu items (Views, Set
Background, Archive) in the sidebar to prevent overflow. Since the
Dropdown component now uses @floating-ui/dom with autoPlacement and
shift middleware, overflow is handled automatically, making the prop
unnecessary.
The color picker had a 500ms debounce before propagating the selected
color to the parent component. Since all usages save via an explicit
button click (not automatically), the debounce only caused a race
condition where the model value could be stale when the user clicked
Save within 500ms of picking a color.
Closesgo-vikunja/vikunja#2312
Add a new settings page for managing user-level webhooks. Extract
webhook form into shared WebhookManager component used by both
project and user webhook settings. Add routing, translations,
and navigation entry.
When viewing a task in modal mode on mobile, both a back button and a close button were displayed, causing confusion. The back button condition `!isModal || isMobile` meant it would show on mobile even in modal mode.
This fix changes the back button to only display when not in modal mode (`!isModal`), ensuring only the close button appears when viewing tasks in a modal on mobile devices.
Also removed the now-unused `isMobile` variable and its import.
This PR surfaces API validation errors from the registration endpoint
directly onto the corresponding form fields, instead of only showing a
generic "invalid data" message. A new `parseValidationErrors` helper
extracts field names and messages from the API's `invalid_fields` array
(e.g. `["email: email is not a valid email address"]`) and maps them to
the appropriate form fields. The Register component integrates this
parser into its error handling, prioritizing client-side validation but
falling back to server-side field errors when present. Errors are
cleared as the user types.
A follow-up commit addressed PR review feedback: the `ValidationError`
interface is now exported from the parser module and reused in
`Register.vue` (eliminating a duplicate `ApiValidationError` interface),
the type guard was tightened to check specifically for `invalid_fields`
rather than broadly matching any object with a `message` property, the
fallback error message always uses the localized translation key instead
of potentially surfacing raw backend messages, and the
`serverValidationErrors` ref uses `Partial<Record>` to accurately
reflect that keys are optional.
🐰 A parser hops through error fields,
Catching field names as each one yields,
Client and server now both agree,
Validation flows harmoniously free!
Whitespace trimmed, no colon? It hops along,
Register form now validated strong! ✨
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: kolaente <k@knt.li>
Replace the global sequenceBuffer (which only tracked key count) with
per-candidate ActiveSequence tracking. This fixes two bugs:
- Sequences with different prefixes could misfire once any sequence
started, since only buffer length was checked, not which sequence
was being matched.
- Single-key shortcuts could fire during an in-progress sequence,
preempting sequence completion depending on binding iteration order.
Replace `any` type assertions with proper types:
- Use WeakMap for element-to-binding mapping instead of expando properties
- Use typed intersection for Firefox's explicitOriginalTarget property
Change e.key to e.code in global keyboard shortcut handlers for
consistency with the new event.code-based shortcut system:
- ProjectList.vue: 'j'/'k'/'Enter' -> 'KeyJ'/'KeyK'/'Enter'
- useGanttBar.ts: 'ArrowLeft'/'ArrowRight' (identical values, for consistency)
- Modal.vue: 'Escape' (identical value, for consistency)
Change all shortcut strings from character-based format to event.code
format:
- Single letters: 't' -> 'KeyT', 's' -> 'KeyS', etc.
- Sequences: 'g o' -> 'KeyG KeyO', etc.
- Modifiers: 'Mod+e' -> 'Mod+KeyE', 'Shift+?' -> 'Shift+Slash'
- edit-shortcut prop: 'e' -> 'KeyE'
Shortcuts like 'Escape' and 'Shift+Delete' remain unchanged as their
event.code values are identical.
Replace the character-based @github/hotkey matching with a custom module
that matches against event.code (physical key position). This makes
shortcuts layout-independent so they work on non-Latin keyboard layouts
(Russian, Greek, Arabic, etc.).
The module provides:
- install/uninstall for declarative element shortcuts (v-shortcut)
- eventToShortcutString for imperative event matching
- Sequence support with 1500ms timeout
- Form field, IME, shadow DOM, and event.repeat guards
- Make parent task bars full height (32px) matching regular bars,
instead of the thin 8px summary bar
- Move collapse/expand chevron to sit right before the bar start
position so it moves with the task during drag/resize
- Remove fixed-position indent indicator lines
- Add light background band with rounded border to visually group
parent tasks with their children, sized to fit the bars