Commit Graph

2755 Commits

Author SHA1 Message Date
MidoriKurage 2d2dbf67a0 fix(tasks): Let getCommentUrl handle frontendUrl including sub-path 2026-04-20 14:28:23 +00:00
MidoriKurage 44122bfe6b fix(frontend/oidc): Prefix frontend base to redirect URL 2026-04-20 14:28:23 +00:00
MidoriKurage 57e2a33dc6 fix(frontend/vite): Configure vite dev proxy to handle frontend path 2026-04-20 14:28:23 +00:00
MidoriKurage 7710e2549e fix(frontend): Fix hard-coded API base in checkAndSetApiUrl.ts 2026-04-20 14:28:23 +00:00
MidoriKurage e31c45c44e fix(frontend): Make sw.ts respect to frontend base URL 2026-04-20 14:28:23 +00:00
kolaente b241c293d0 fix(frontend): restore tablet pagination layout (space-between + flex order)
The Bulma partial applied justify-content: space-between on .pagination and
flex-order 1/2/3 on prev/list/next inside a tablet media query under
.is-centered — the port missed both. Pixel-diff against main is now zero.
2026-04-20 10:38:08 +00:00
kolaente 8f64836999 refactor(frontend): extract PaginationItem to own pagination-link styling
BasePagination was reaching across slot boundaries with :deep() to style
.pagination-previous / -next / -link — markup it doesn't actually render.
Move that markup and the related scoped rules into a new PaginationItem
component that polymorphically renders RouterLink (when `to` is given)
or BaseButton (emit-based). BasePagination keeps only the scaffold it
actually owns: .pagination, .pagination-list, .pagination-ellipsis.

Pagination.vue and PaginationEmit.vue become thin wrappers around
BasePagination + PaginationItem; no more raw pagination-* class usage or
BaseButton imports in the emit wrapper.

The .app-container.has-background / .link-share-container.has-background
theme override moves with the .pagination-link rules into PaginationItem
as its own unscoped <style> block.

Result: 0 remaining :deep(.pagination-*) selectors (was 14).
2026-04-20 10:38:08 +00:00
kolaente 5ea7853dd6 refactor(frontend): port pagination rules into BasePagination and drop Bulma import
The Bulma components/pagination partial is only used by BasePagination
and its two wrappers (Pagination.vue, PaginationEmit.vue); no other
component renders raw .pagination-* markup. Ports the rules we actually
use (base layout, item sizing, hover/focus/disabled states, is-current
styling, mobile/tablet breakpoints) into BasePagination's scoped styles,
using :deep() to reach slotted children. The theme override for
.pagination-link on .has-background containers moves into an unscoped
style block on the same component. Drops the now-unused @import.
2026-04-20 10:38:08 +00:00
renovate[bot] 326874d94c chore(deps): update dev-dependencies 2026-04-20 06:18:12 +00:00
Frederick [Bot] 56aef03697 chore(i18n): update translations via Crowdin 2026-04-19 01:46:56 +00:00
Frederick [Bot] 9b46ad8ecc chore(i18n): update translations via Crowdin 2026-04-18 01:23:08 +00:00
kolaente 89af0a6c14 refactor(frontend): use FormCheckbox for remember-me on Login 2026-04-17 12:54:17 +00:00
kolaente b9f6eabe2c refactor(frontend): use form primitives in WebhookManager 2026-04-17 12:54:17 +00:00
kolaente cab970b59b refactor(frontend): use form primitives in user settings General view 2026-04-17 12:54:17 +00:00
kolaente a6811a922a refactor(frontend): support two-col layout on FormField 2026-04-17 12:54:17 +00:00
kolaente 59e7c9bce3 feat(frontend): add FormCheckbox primitive component 2026-04-17 12:54:17 +00:00
kolaente 740546ee5a feat(frontend): add FormSelect primitive component 2026-04-17 12:54:17 +00:00
kolaente 875f685caf feat(frontend): add FormInput primitive component 2026-04-17 12:54:17 +00:00
kolaente 10e5fa915a refactor(frontend): drop Bulma components/navbar import
.navbar and .navbar-end are only used in AppHeader.vue. Ports the
relevant rules (z-index 30 and min-block-size: $navbar-height) into
its scoped <style> block and drops the partial import.
2026-04-17 07:43:35 +00:00
dependabot[bot] 10ec3b55b0 chore(deps): bump dompurify from 3.3.2 to 3.4.0 in /frontend
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.2 to 3.4.0.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.2...3.4.0)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 13:01:57 +00:00
Tink 95ec3325c2
refactor(frontend): migrate .box to Card and drop Bulma elements/box (#2640) 2026-04-16 14:14:36 +02:00
Tink 19ee7f26ee
refactor(frontend): drop Bulma components/card import (#2639) 2026-04-16 14:12:36 +02:00
Frederick [Bot] 3120c2b12c chore(i18n): update translations via Crowdin 2026-04-16 01:46:56 +00:00
kolaente 50465818ae refactor(frontend): drop Bulma components/media import
The .media / .media-left / .media-content classes are only used in
Comments.vue. Ports the relevant rules into its scoped <style> block
and drops the partial import.
2026-04-15 20:15:42 +00:00
kolaente 3c3b1820a1 refactor(frontend): port is-pulled-right locally and drop Bulma float helper
Only .is-pulled-right is used (3 callsites); .is-pulled-left and
.is-clearfix from Bulma's helpers/float partial have zero usage. Ports the
one needed rule into theme/helpers.scss so the Bulma import can go.
2026-04-15 20:12:45 +00:00
renovate[bot] 2ae194e943 chore(deps): update dependency postcss to v8.5.10 2026-04-15 16:25:26 +00:00
renovate[bot] 85dbef8330 chore(deps): update dependency stylelint to v17.8.0 2026-04-15 15:49:30 +00:00
kolaente d09ef36bd4 fix(frontend): guard Object.keys against null in refactored helpers
typeof null === 'object', so null slipped past the type guards in
objectToCamelCase/objectToSnakeCase/prepareParams. The original
for...in loops silently iterated nothing on null; Object.keys(null)
throws. Also guard saveCollapsedBucketState where state[projectId]
may be undefined.
2026-04-15 11:44:47 +00:00
kolaente dd83e0d42b refactor(frontend): replace reverse-index splice loops with findIndex/filter
Single-match removals use findIndex + splice; the reminder-null cleanup
uses filter since model.reminders is on a local shallow clone.
2026-04-15 11:44:47 +00:00
kolaente 2c6029eac4 refactor(frontend): replace for...in usages and forbid via lint rule
Replaces 33 for...in loops across 18 files with for...of + Object.keys/entries
or indexed for loops. for...in iterates enumerable string keys including
inherited ones, which is especially risky on reactive arrays (tasks, labels,
assignees, etc.) where polyfilled properties may appear.

Loops that mutate via splice during iteration now iterate backwards to avoid
index-shift bugs. Adds a no-restricted-syntax ESLint rule forbidding
ForInStatement to prevent regressions.

Closes #513
2026-04-15 11:44:47 +00:00
kolaente 95180a341d refactor(frontend): drop unused Bulma form/file partial import
Every file input in the codebase is hidden (via class="is-hidden" or
scoped display:none) and triggered programmatically by a custom XButton.
None of Bulma's .file / .file-label / .file-cta / .file-input / .file-name /
.file-icon classes are used anywhere in .vue files, so the partial is dead
code.
2026-04-15 11:06:11 +00:00
kolaente 39c804f460 refactor(frontend): drop unused Bulma modal partial import
Vikunja's Modal.vue uses a native <dialog> element with its own locally-
scoped classes (modal-dialog, modal-container, modal-content, modal-header).
None of Bulma's modal classes (.modal, .modal-background, .modal-card*) are
used anywhere in the app. The two CSS variables this partial provided
(--modal-card-head-padding, --modal-content-spacing-tablet) were inlined in
the two callers in the previous commits, so the whole partial is now dead
code.

Modal.vue already had several 'reset bulma' overrides fighting the default
rules Bulma applied to .modal-content; those can be cleaned up in a
follow-up.
2026-04-15 10:56:48 +00:00
kolaente d05fd4dbb2 refactor(frontend): inline modal-content-spacing-tablet in PDF preview
The --modal-content-spacing-tablet CSS variable is provided by Bulma's
components/modal partial. Inlining Bulma's default (40px) lets us drop that
partial.
2026-04-15 10:56:48 +00:00
kolaente 0b2f625f06 refactor(frontend): inline modal-card-head-padding in Card footer
The --modal-card-head-padding CSS variable is provided by Bulma's
components/modal partial. Inlining Bulma's default (20px) lets us drop that
partial without needing a local redeclaration.
2026-04-15 10:56:48 +00:00
kolaente 9899979ca7 docs(frontend): document styles architecture and token system 2026-04-15 10:02:39 +00:00
kolaente 02ae01ad80 chore(frontend): enable vue/multi-word-component-names with legacy allowlist 2026-04-15 09:58:55 +00:00
kolaente 21609127a1 fix(frontend): guard caldav and totp settings routes when disabled 2026-04-15 09:57:17 +00:00
kolaente 91d5cfb1c0 fix(frontend): render editor popups inside modal dialog top-layer
Native <dialog> elements opened with showModal() render in the browser's
top-layer. Popups appended to document.body end up behind the dialog
regardless of z-index, which broke the slash-command menu and the user
mention suggestion inside the task detail modal.

Append the popups to the nearest open <dialog> ancestor of the editor
(falling back to document.body) so they join the same top-layer stacking
context.
2026-04-15 08:39:24 +00:00
kolaente a1fbc277be
fix(deps): patch follow-redirects and basic-ftp security vulnerabilities
Update follow-redirects to 1.16.0 (fixes auth header leak on cross-domain
redirects) and basic-ftp to 5.2.2 (fixes CRLF injection in FTP commands).
2026-04-14 20:49:42 +02:00
kolaente f208279dd2 test(editor): add e2e for emoji autocomplete 2026-04-14 13:48:49 +00:00
kolaente c0f05b6277 feat(editor): register emoji autocomplete extension 2026-04-14 13:48:49 +00:00
kolaente 7ab2804129 feat(editor): add emoji TipTap extension 2026-04-14 13:48:49 +00:00
kolaente 02d4dd1631 feat(editor): add emoji suggestion handler 2026-04-14 13:48:49 +00:00
kolaente 88136ed45e feat(editor): add EmojiList popup component 2026-04-14 13:48:49 +00:00
kolaente 542cab5ef6 feat(editor): add lazy emoji data loader and filter 2026-04-14 13:48:49 +00:00
kolaente 7227c59f5e test(e2e/kanban): seed the view only once with done_bucket_id 2026-04-14 11:32:14 +00:00
kolaente af6923524f test(e2e/kanban): cover recurring task drag to done bucket (#2618) 2026-04-14 11:32:14 +00:00
kolaente d389408618 test(kanban): cover moveTaskToBucket 2026-04-14 11:32:14 +00:00
kolaente 13c4aec461 fix(frontend/kanban): honor server bucket redirect on drag (#2618) 2026-04-14 11:32:14 +00:00
renovate[bot] c68649faf4 chore(deps): update dev-dependencies 2026-04-14 10:51:01 +00:00
Frederick [Bot] 8bde434676 chore(i18n): update translations via Crowdin 2026-04-14 01:29:51 +00:00
renovate[bot] a3ac01346a chore(deps): update dev-dependencies 2026-04-13 10:14:34 +00:00
Frederick [Bot] 5ef01965e5 chore(i18n): update translations via Crowdin 2026-04-13 01:48:06 +00:00
renovate[bot] 160495b84e chore(deps): update dependency stylelint to v17.7.0 2026-04-12 14:42:19 +00:00
kolaente f6693f81a2 test(e2e): cover quick add auto-attaching default reminders 2026-04-11 21:51:41 +00:00
kolaente 5afd066a13 feat(tasks): apply default reminders to quick-add tasks with due date
When a user has configured default reminders in their frontend settings,
those are cloned onto every task created via quick-add magic that has a
parsed due date. Tasks without a due date are silently skipped.

The buildDefaultRemindersForQuickAdd helper is exported as a pure
function so it can be unit-tested without stubbing the Pinia store.
2026-04-11 21:51:41 +00:00
kolaente 338d4d8b76 feat(settings): surface quick add default reminders in user settings
Adds the settings field next to the quick add magic mode select, hidden
when that mode is set to Disabled. Uses Reminders.vue directly with
allow-absolute=false and default-relative-to pinned to due date.
2026-04-11 21:51:41 +00:00
kolaente 6c9753328b feat(i18n): add strings for quick add default reminders 2026-04-11 21:51:41 +00:00
kolaente dc4b7a5510 refactor(reminders): make Reminders.vue take ITaskReminder[] directly
Reminders.vue only read three task fields (dueDate/startDate/endDate)
and wrote one back (reminders). The ITask coupling was accidental.

Flip the prop to ITaskReminder[] and pass defaultRelativeTo / allowAbsolute
as plain props. TaskDetailView now owns the due/start/end priority
computation and binds v-model="task.reminders" directly. This also lets
the settings page reuse Reminders.vue for configuring default reminders.
2026-04-11 21:51:41 +00:00
kolaente b61ad9d46a feat(reminders): add allowAbsolute prop to ReminderDetail
Adds an allowAbsolute prop to ReminderDetail that hides the 'Date and
time' option when set to false, and a lockRelativeTo prop on
ReminderPeriod that hides the relativeTo select and forces the chosen
value. ReminderDetail threads them together so that when absolute
reminders are disallowed, the Custom form can only produce reminders
that anchor to defaultRelativeTo.
2026-04-11 21:51:41 +00:00
kolaente e85f3fd84c feat(settings): add quickAddDefaultReminders field to frontend settings 2026-04-11 21:51:41 +00:00
kolaente c06a33fb63 test(e2e): mirror task id to index in TaskFactory
Multiple TaskFactory.create(1, {id: N, ...}, false) calls for the same
project were all defaulting to index=1 (from {increment} with count=1),
which collides on the newly added UNIQUE(project_id, index) constraint.
Mirror the numeric id override to index so each row stays unique and
matches the id == index convention used by raw seedTasks helpers.

Fixes the e2e playwright seed failures in subtask-duplicates, list/table
filter/search, kanban filter/search, and overview specs.
2026-04-11 20:44:28 +00:00
kolaente 113b77e92f fix(modal): skip showModal if enabled flipped false before mount
Re-check props.enabled inside the dialogRef watcher. The watcher fires
once Vue mounts the <dialog>, but the caller may have flipped enabled
back to false between the openDialog() call and the mount flush. In that
case the prop state is disabled and we must not open the dialog.

Addresses augmentcode review on #2604.
2026-04-11 19:00:43 +00:00
kolaente e01a599418 fix(modal): clear stale data-closing flag when re-opened mid-close
If the modal is re-enabled within the 150ms close transition the
<dialog> element is still mounted and [open], so the dialogRef watcher
does not re-fire. Clear the leftover data-closing flag directly in
openDialog() so the dialog doesn't remain stuck at opacity 0.

Addresses augmentcode review on #2604.
2026-04-11 19:00:43 +00:00
kolaente e932ee759a fix(modal): open dialog reliably in electron desktop
Replace the nextTick-based showModal() call with a watch on the template
ref so the dialog is opened exactly when the <dialog> element mounts.
The previous implementation could silently skip showModal() if the mount
was deferred past the first nextTick, leaving the dialog in the DOM with
opacity: 0 and no click target. Observed in the Vikunja Desktop v2.3.0
Electron build where the search (quick actions) button was unresponsive.

Closes #2590
2026-04-11 19:00:43 +00:00
kolaente f29f985386 test(modal): cover open race for #2590 2026-04-11 19:00:43 +00:00
Frederick [Bot] 50d6926b56 chore(i18n): update translations via Crowdin 2026-04-11 01:20:45 +00:00
renovate[bot] df7a5c645c chore(deps): update dependency wait-on to v9.0.5 2026-04-10 22:57:21 +00:00
dependabot[bot] e8c20b1244 chore(deps): bump axios from 1.13.5 to 1.15.0 in /frontend
Bumps [axios](https://github.com/axios/axios) from 1.13.5 to 1.15.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.5...v1.15.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 09:58:30 +00:00
kolaente 28b537837f
chore: v2.3.0 release preparations 2026-04-09 20:43:40 +02:00
kolaente b642b2a453 feat(auth): prompt for TOTP code in the OIDC callback flow
When the backend reports that 2FA is required (412/1017), the OIDC
callback view now shows a TOTP input and restarts the OIDC dance
with the typed passcode stashed in localStorage so it can be
submitted alongside a fresh authorization code.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente 546db0dc21 feat(auth): plumb totp passcode through openIdAuth action
Allows the OpenIdAuth view to resubmit the OIDC callback with a
TOTP passcode after a 412/1017 response from the backend.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente 27a88dd17a
fix(deps): bump basic-ftp override to 5.2.1 to patch CRLF injection
Resolves Dependabot alert #183 (high severity): basic-ftp 5.2.0 is
vulnerable to FTP command injection via CRLF. The package is pulled in
as a dev-only transitive dependency by @histoire/plugin-screenshot.
2026-04-09 15:34:00 +02:00
kolaente 8814cb37d8
fix(tasks): vertically center checkbox in project task row
The tooltip span wrapping the checkbox used the inherited line-height
(~24px), so the 18px inline-block checkbox sat on the baseline and
appeared misaligned with the task text. Making the span an inline-flex
container collapses it to the checkbox size and centers it properly.
2026-04-09 15:30:27 +02:00
kolaente a574d623b1 test: add e2e regression test for link share loop while logged in
Covers #2546: a logged-in user navigating to a public link share URL
used to bounce infinitely between /share/:hash/auth and the project
view, stranding the user on an empty NoAuthWrapper shell. Two distinct
issues in checkAuth() produced the same symptom:

  1. The 1-minute debounce skipped re-parsing the new link share JWT
     when the user was already authenticated.
  2. The "same user, skip setUser" fast path compared only `id`, so a
     logged-in user whose id collided with the link share's id kept
     the USER `info.value.type` and `authLinkShare` never flipped.

The test pins both the logged-in user and the link share to the same
numeric id so it exercises the collision path, which catches both
regressions at once.
2026-04-09 10:20:46 +00:00
kolaente 432c5f2817 fix: include type in checkAuth's same-user skip check
Users and link shares share the same numeric id space in JWTs. When a
logged-in user opened a link share whose id happened to match their own
user id, checkAuth() would see `info.value.id === jwtUser.id` and skip
`setUser()`, leaving `info.value.type` as USER even though the new token
was a LINK_SHARE. As a result, `authLinkShare` never flipped to true and
the router guard bounced between /share/:hash/auth and the project view,
stranding the user on an empty NoAuthWrapper shell.

Compare on type as well so USER→LINK_SHARE transitions always replace
the user object.

Refs #2546
2026-04-09 10:20:46 +00:00
kolaente 2000732e35 fix: skip refreshUserInfo for link share tokens to prevent logout loop 2026-04-09 10:20:46 +00:00
kolaente 1d3a234b05 fix: reset checkAuth debounce in linkShareAuth to prevent redirect loop
When a logged-in user opens a public link share, the 1-minute debounce
on checkAuth() caused it to skip re-parsing the new link share JWT.
This left authLinkShare as false, triggering an infinite redirect loop
in the router guard.

Fixes #2546
2026-04-09 10:20:46 +00:00
kolaente 91728c0273 test: wire up API URL for anonymous link share e2e tests
The anonymous link share tests don't use the authenticatedPage fixture
(which implicitly calls setupApiUrl via login()), so the browser was
falling back to the default `window.API_URL = '/api/v1'` baked into
index.html. That relative path resolved against the preview server port
and never reached the API, causing the tests to hang on the NoAuth
"Welcome Back" page waiting for elements that never rendered.

Adding a beforeEach that calls setupApiUrl() restores these tests.
2026-04-09 10:20:46 +00:00
renovate[bot] 4415485675 chore(deps): update dependency vitest to v4.1.4 2026-04-09 08:59:51 +00:00
kolaente e7bc5a31e4 docs(shortcuts): show platform-aware delete key in keyboard shortcuts panel 2026-04-09 08:07:48 +00:00
kolaente cee2babc58 feat(tasks): use platform-aware delete shortcut on task detail view 2026-04-09 08:07:48 +00:00
Frederick [Bot] 36cec5ccca chore(i18n): update translations via Crowdin 2026-04-09 01:16:09 +00:00
kolaente 10e7d2532e fix: derive workbox version from package.json at build time
Instead of hardcoding the workbox version string in the service worker,
read it from workbox-precaching/package.json via Vite's define option.
This ensures the service worker always references the correct workbox
version that is actually installed.

Resolves #2549
2026-04-08 08:42:11 +00:00
renovate[bot] e898c01e3d chore(deps): update dev-dependencies 2026-04-08 08:03:18 +00:00
Frederick [Bot] f528bcc276 chore(i18n): update translations via Crowdin 2026-04-08 01:25:14 +00:00
kolaente 3437f98dc3 feat(migration): add skip rows option to CSV import
Allow users to skip the first N data rows when importing CSV files.
This is useful when the CSV contains metadata rows before the actual
task data begins. Adds skip_rows to ImportConfig (backend) and a
number input in the parsing options UI (frontend).
2026-04-07 15:20:06 +00:00
Claude f555762def feat(migration): add generic CSV import with column mapping
Add a new CSV migration module that allows users to import tasks from
any CSV file with custom column mapping and parsing options.

Backend changes:
- New CSV migrator module with detection, preview, and import endpoints
- Auto-detection of delimiter, quote character, and date format
- Suggested column mappings based on column name patterns
- Transactional import using InsertFromStructure

Frontend changes:
- New CSV migration UI with two-step flow (upload -> mapping -> import)
- Column mapping selectors for all task attributes
- Live preview showing first 5 tasks with current mapping
- Parsing option controls for delimiter and date format

The CSV migrator creates a parent "Imported from CSV" project with
child projects based on the project column if provided, or a default
"Tasks" project for tasks without a specified project.
2026-04-07 15:20:06 +00:00
surfingbytes 84f4c16425
feat(user): add option to hide last viewed projects on overview page (#2429) 2026-04-07 16:56:13 +02:00
kolaente 8a8d187065 chore(frontend): deduplicate pnpm dependencies 2026-04-07 14:22:04 +00:00
renovate[bot] 11299d773f chore(deps): update dependency vitest to v4.1.3 2026-04-07 13:43:01 +00:00
kolaente 20249ee68c style(sort): position popup aligned to header right edge 2026-04-07 13:41:13 +00:00
kolaente 326427a242 feat(sort): persist sort selection to URL query parameter
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.
2026-04-07 13:41:13 +00:00
kolaente 408e5b347c feat(sort): add sorting popup for list view 2026-04-07 13:41:13 +00:00
kolaente b20df2ef63
fix(deps): update brace-expansion to 5.0.5
Fixes zero-step sequence causing process hang and memory
exhaustion (Dependabot #168).
2026-04-07 15:39:33 +02:00
kolaente efc9b41349
fix(deps): update lodash to 4.18.1
Fixes code injection via _.template (Dependabot #176, #178) and
prototype pollution via _.unset/_.omit (Dependabot #175, #177).
2026-04-07 15:38:52 +02:00
kolaente f40eddd4e3
fix(deps): update defu to 6.1.7
Fixes prototype pollution via __proto__ key (Dependabot #180).
2026-04-07 15:38:17 +02:00
kolaente 34480ef513 fix(migration): center and style migrator logos on migration page
Use inline-flex layout to center logos with titles below. Constrain
logo size with max-block-size and use logical CSS properties.
2026-04-07 12:05:47 +00:00
kolaente 1a1fd780ec feat(migration): add WeKan to migration page with logo
Register WeKan in the AvailableMigrators list and add the frontend
migrator entry with the WeKan logo, referenced as "WeKan ®".
2026-04-07 12:05:47 +00:00
renovate[bot] 33886d2e3c chore(deps): update dev-dependencies 2026-04-06 16:23:31 +00:00
Frederick [Bot] 41a5087198 chore(i18n): update translations via Crowdin 2026-04-06 01:26:55 +00:00
kolaente 4b3b5bb87c docs(helpers): explain djb2 seed constant in stringHash 2026-04-05 12:24:45 +00:00
kolaente 65b6e55252 test(e2e): relax home greeting assertions for rotating pool 2026-04-05 12:24:45 +00:00
kolaente b9c41e0cbf feat(home): rotate greetings from a deterministic per-user daily pool 2026-04-05 12:24:45 +00:00
kolaente fad432a072 i18n: add rotating home greeting variants 2026-04-05 12:24:45 +00:00
kolaente b0bc41291e feat(helpers): add deterministic stringHash for stable daily selection 2026-04-05 12:24:45 +00:00
kolaente d45ae31d8c fix(gantt): preserve query parameters when closing task modal
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.
2026-04-05 11:31:37 +00:00
kolaente 642134d16f test(gantt): add e2e test for date range preservation after task modal close
Verifies that opening and closing a task modal on the Gantt view
does not lose the date range query parameters.
2026-04-05 11:31:37 +00:00
kolaente d152fa8475 fix(gantt): use reactive date range in Flatpickr config to prevent reset on task update
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
2026-04-05 11:31:37 +00:00
kolaente 297c0c1d8b fix(e2e): seed project in empty-tasks overview test
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.
2026-04-05 09:48:09 +00:00
kolaente adcc74b056 fix: make apiContext auto-fixture and fix remaining view ID conflicts 2026-04-05 09:48:09 +00:00
kolaente 4888b1d8ca fix: move truncateAll to apiContext fixture and fix view ID conflicts 2026-04-05 09:48:09 +00:00
kolaente aa1202fea8 chore: remove redundant truncate calls now that all tables are wiped before each test 2026-04-05 09:48:09 +00:00
kolaente 2ee8ad4109 feat: truncate all tables before each e2e test for clean isolation 2026-04-05 09:48:09 +00:00
kolaente f477da48ec feat: add Factory.truncateAll() helper for e2e tests 2026-04-05 09:48:09 +00:00
kolaente 0834d19f9c
feat: remove flexsearch dependency and replace with simple string filtering (#2542) 2026-04-04 21:41:25 +02:00
kolaente f5752b97e9
feat: add inline PDF viewer for task attachments (#2541) 2026-04-04 21:25:54 +02:00
renovate[bot] 33d607714d chore(deps): update dependency caniuse-lite to v1.0.30001785 2026-04-04 18:38:07 +00:00
kolaente 841b458a5f fix: pass saved filter context to subtask visibility check
When viewing tasks through a saved filter, pass isFilteredView=true
to shouldShowTaskInListView so subtasks are not incorrectly hidden.

Ref: #2494
2026-04-03 19:25:46 +00:00
kolaente d895053d2e fix: show subtasks in saved filter views regardless of parent presence
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
2026-04-03 19:25:46 +00:00
kolaente 616ac8b95f test: add failing tests for subtask visibility in filtered views
Add test cases to verify that subtasks are shown in saved filter views
regardless of whether their parent task is also in the results.

Ref: #2494
2026-04-03 19:25:46 +00:00
kolaente 174c67cfd8 fix(gantt): isolate chart stacking context so date picker renders above it
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
2026-04-03 19:07:49 +00:00
kolaente f25147d09c fix(gantt): ensure chart container fills viewport width for narrow date ranges
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
2026-04-03 19:07:49 +00:00
kolaente 48a91ce32c fix(frontend): prevent drag handle from overlapping project color in sidebar
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.
2026-04-03 19:05:10 +00:00
kolaente a57cbd3e51 feat: add tooltip to readonly checkbox explaining why it's not clickable 2026-04-03 19:01:45 +00:00
kolaente c5bce07a25 test(e2e): add test for read-only checkbox on overview page
Verifies that tasks from read-only shared projects have disabled
checkboxes on the overview page, while tasks from owned projects
remain interactive.

Refs #2399
2026-04-03 19:01:45 +00:00
kolaente 063155a46b fix(overview): disable checkbox for read-only tasks on overview page
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
2026-04-03 19:01:45 +00:00
kolaente 4f232957c4 fix(auth): add retry and logging for token refresh failures
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
2026-04-03 18:45:59 +00:00
kolaente fd8a8ecba2 fix(auth): normalize API base URL to prevent refresh cookie path mismatch
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
2026-04-03 18:45:59 +00:00
renovate[bot] 12ba9ff985 chore(deps): update dev-dependencies 2026-04-03 17:52:24 +00:00
renovate[bot] ea54f3eb85 chore(deps): update dependency ws to v8.20.0 2026-04-03 16:57:34 +00:00
renovate[bot] b69564a77c chore(deps): pin dependencies 2026-04-03 16:16:07 +00:00
Frederick [Bot] f87f3e36e9 chore(i18n): update translations via Crowdin 2026-04-03 01:23:06 +00:00
kolaente 132187e451 fix(e2e): truncate bucket data in bucket-select tests
Truncate buckets, task_buckets, and task_relations before seeding to
prevent leftover data from previous tests causing false positives
(e.g., bucket selector appearing when it shouldn't).
2026-04-02 16:30:23 +00:00
kolaente 4cd79088d1 test: add WebSocket e2e tests
Add comprehensive end-to-end tests for the WebSocket system:

- Protocol tests: auth (valid/invalid token, timeout, double auth),
  subscriptions (valid/invalid event, auth required, unsubscribe),
  message delivery (notification on team add, doer exclusion,
  multi-connection)
- Frontend integration tests: notification badge update, dropdown
  rendering, and logout cleanup via browser-level Playwright tests
- Comment notification test: full flow where user B mentions user A
  in a task comment and user A receives real-time WebSocket notification

Includes ws test dependency, shared test helper utilities, and
cascade-truncation of notifications when truncating users to prevent
test pollution.
2026-04-02 16:30:23 +00:00
kolaente 09232ed880 feat(websocket): add frontend WebSocket support
Add useWebSocket composable with:
- Auto-connect on login, disconnect on logout
- Exponential backoff with ±25% jitter for reconnects
- Auth failure detection to prevent reconnect loops
- Trailing slash stripping from API_URL
- Overlapping reconnect prevention
- visibilityState check for fallback polling

Replace notification polling with real-time WebSocket push in the
Notifications component. Initial state is still loaded via REST on
mount, with fallback polling when WebSocket is disconnected. Incoming
notifications are deduplicated against already-loaded REST data.
Notifications are reloaded via REST on WS disconnect to catch missed
events.
2026-04-02 16:30:23 +00:00
Lars de Ridder cb4f92980b
feat(task): allow changing bucket from task detail view (#2233) 2026-04-02 12:18:34 +02:00
renovate[bot] d73222e4a7 chore(deps): update dependency esbuild to v0.27.5 2026-04-02 08:23:19 +00:00
kolaente cef03cb2a0 refactor: replace Modal div-based implementation with native dialog element
Replace the custom div-based Modal with the native HTML <dialog> element
using showModal()/close() API. Uses CSS opacity transitions with a
data-closing attribute for Firefox-compatible close animations, Teleport
to body, and focus save/restore. Updates E2E test selectors and fixes
QuickAddOverlay selectors for the new dialog structure.
2026-04-01 22:27:13 +00:00
kolaente bc47826690 feat(frontend): add configurable quick entry shortcut setting
Add desktopQuickEntryShortcut to frontend settings with a Desktop
App section in General settings, only visible when running in the
Electron app. The setting syncs to the desktop main process via
IPC whenever settings are loaded or saved.
2026-04-01 21:38:38 +00:00
kolaente c8349df8b6 feat(desktop): open task in main window with Ctrl/Cmd+Enter
When creating a task via quick entry, pressing Ctrl+Enter (or
Cmd+Enter on macOS) creates the task and opens it in the main
Vikunja window. Adds show-main-window IPC to bring the main
window to focus.
2026-04-01 21:38:38 +00:00
kolaente 37389d6bdb feat(desktop): add quick entry window, global shortcut, and system tray 2026-04-01 21:38:38 +00:00
kolaente 92cc070b1e feat(frontend): listen for cross-window task creation via BroadcastChannel 2026-04-01 21:38:38 +00:00
kolaente 8dc96d61bd feat(frontend): adapt QuickActions for quick-add mode behavior 2026-04-01 21:38:38 +00:00
kolaente 9072ca84d5 feat(frontend): route quick-add mode to QuickAddOverlay in App.vue 2026-04-01 21:38:38 +00:00
kolaente ff4e84a800 feat(frontend): add QuickAddOverlay component for quick-entry window 2026-04-01 21:38:38 +00:00
kolaente d72a3a8c0d feat(frontend): add useQuickAddMode composable for quick-add detection 2026-04-01 21:38:38 +00:00
kolaente af7eaa9aea
fix(desktop): use stored URL instead of window.API_URL in template
window is not accessible as a global in Vue templates, causing
"Cannot read properties of undefined (reading 'API_URL')" when
clicking sign in on the desktop app.
2026-04-01 20:53:29 +02:00
renovate[bot] 59ebfa3b2c chore(deps): update dependency caniuse-lite to v1.0.30001784 2026-04-01 09:17:36 +00:00
Frederick [Bot] 88c8d7a73d chore(i18n): update translations via Crowdin 2026-04-01 01:44:10 +00:00
kolaente cdd46c0d6c fix: add proper autocomplete and name attributes to email update form
Adds name="email" to the email field and fixes the password field's
autocomplete from the invalid "password" to "current-password", also
adding name="current-password". This helps password managers correctly
identify the form as a settings change rather than a login form,
preventing them from autofilling the username into the email field.

Closes go-vikunja/vikunja#2512
2026-03-31 21:57:12 +00:00
renovate[bot] 020aa899f8 chore(deps): update dependency browserslist to v4.28.2 2026-03-31 21:21:12 +00:00
renovate[bot] 167380a01e chore(deps): update dependency @typescript-eslint/parser to v8.58.0 2026-03-30 20:13:08 +00:00
kolaente 495f34f60e feat: show close-tab message after OAuth redirect
Show a "You can close this tab now" message after the OAuth
authorize page redirects to the desktop app, instead of leaving
a stale "Authenticating..." message in the browser tab.
2026-03-30 20:12:25 +00:00
kolaente a12002de6d feat: add server selection UI for desktop OAuth login
Add a server selection screen matching the mobile app UX with
Vikunja Cloud, Try the Demo, and Custom Server URL options.
Extract all desktop login logic into a dedicated DesktopLogin
component. Use the existing ApiConfig component for custom server
URL input. Skip loading server config on startup to avoid showing
motd/demo popups on the login screen.
2026-03-30 20:12:25 +00:00
kolaente dd7532a57a feat: add OAuth PKCE authentication flow to desktop app
Add a complete OAuth 2.0 PKCE flow for the Electron desktop app:

- Implement PKCE code generation and token exchange in Electron
- Register custom protocol handler (vikunja-desktop://) for deep links
- Handle deep link race conditions (buffered URLs, process.argv fallback)
- Prevent duplicate IPC listener accumulation on re-mount
- Preserve sub-paths in OAuth authorize URL for non-root deployments
- Add token refresh support using Electron's net module
2026-03-30 20:12:25 +00:00
renovate[bot] 1a3a18e42b chore(deps): update dependency @typescript-eslint/eslint-plugin to v8.58.0 2026-03-30 19:12:16 +00:00
kolaente c2cfcb4684 feat: add API token hint to CalDAV settings page 2026-03-30 12:09:53 +00:00
renovate[bot] 1c0513de10 chore(deps): update dev-dependencies 2026-03-30 10:24:04 +00:00
Frederick [Bot] fb8c937d77 chore(i18n): update translations via Crowdin 2026-03-29 01:25:40 +00:00
dependabot[bot] 21a450b21f chore(deps): bump serialize-javascript from 7.0.3 to 7.0.5 in /frontend
Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 7.0.3 to 7.0.5.
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: serialize-javascript
  dependency-version: 7.0.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-28 23:35:34 +00:00
Frederick [Bot] ffb291c966 chore(i18n): update translations via Crowdin 2026-03-28 01:16:36 +00:00
renovate[bot] 8d958aef62 chore(deps): update dev-dependencies 2026-03-27 23:06:28 +00:00
kolaente 649043aceb test: add tests for OAuth 2.0 authorization flow
Add web tests covering the authorize endpoint, token exchange, PKCE
verification, single-use codes, and refresh token rotation. Add unit
tests for redirect URI validation and PKCE. Add E2E test for the full
browser-based authorization code flow with login redirect.

Extract setupApiUrl helper for E2E tests to avoid duplication.
2026-03-27 23:05:04 +00:00
kolaente 0471f8a729 feat: add frontend OAuth authorize route and component
Add /oauth/authorize frontend route with OAuthAuthorize.vue that
handles the OAuth authorization flow: validates required query params,
calls the API to generate an authorization code, and redirects to the
callback URI. Authentication is handled by the standard router guard.
2026-03-27 23:05:04 +00:00
Frederick [Bot] a2e19f8d38 chore(i18n): update translations via Crowdin 2026-03-27 01:22:35 +00:00
renovate[bot] 9d8c6a0a72 chore(deps): update dev-dependencies 2026-03-26 09:02:42 +00:00
Miikka Kulmala b89b402bc2
feat: improve wording and UX around CalDAV tokens (#2476) 2026-03-26 10:02:04 +01:00
Frederick [Bot] 39238333dd chore(i18n): update translations via Crowdin 2026-03-26 01:22:26 +00:00
kolaente 98ac119f44
fix(deps): update yaml to fix stack overflow vulnerability
Updates yaml from 2.5.0 to 2.8.3 in the frontend workspace to
address stack overflow via deeply nested YAML collections.
2026-03-25 23:33:56 +01:00
kolaente d60e2f6685
fix(deps): update picomatch to fix ReDoS and method injection vulnerabilities
Updates picomatch to 2.3.2 and 4.0.4 in the frontend workspace to
address CVE for ReDoS via extglob quantifiers and method injection
in POSIX character classes.
2026-03-25 23:31:28 +01:00
kolaente 44d01a0f82 refactor: rename parseTaskText module to quickAddMagic
Rename the frontend parsing module from `parseTaskText` to `quickAddMagic`
for clarity. The module handles much more than text parsing — it's the
core of the quick add magic feature. This rename makes its purpose
immediately obvious and aligns with how the feature is referenced
throughout the UI and documentation.

No logic changes — only directory/file renames and import updates.
2026-03-25 09:38:41 +00:00
kolaente dca041459f feat: show info when saved homepage filter is ignored for label browsing 2026-03-24 21:55:26 +00:00
kolaente fd4f7accc3 fix: ignore saved homepage filter when browsing by label 2026-03-24 21:55:26 +00:00
kolaente 7208c11556 feat: add translation for saved filter ignored message 2026-03-24 21:55:26 +00:00
kolaente 6d2bf1f084 fix: resolve TDZ error on password update settings page
Move the watchEffect call after the validate function declaration
to fix "Cannot access 'c' before initialization" error that occurred
when visiting the password update page with validateInitially=true.

Fixes #2463
2026-03-24 15:17:32 +00:00
renovate[bot] 4b16d72e28 chore(deps): update dev-dependencies 2026-03-24 15:14:31 +00:00
Frederick [Bot] 74ecc6fffd chore(i18n): update translations via Crowdin 2026-03-24 01:11:44 +00:00
kolaente 772316b47f
chore: v2.2.2 release preparations 2026-03-23 21:49:15 +01:00
kolaente 74d1bddb3a fix: hide link sharing section in UI for non-admin users 2026-03-23 20:39:31 +00:00
kolaente 6d5d3e051f
chore: v2.2.1 release preparations 2026-03-23 19:50:19 +01:00
renovate[bot] 2c1104ca86 chore(deps): update dev-dependencies to v8.57.2 2026-03-23 18:30:13 +00:00
kolaente 07b9742d98 fix: skip quick add magic parsing when text is wrapped in quotes
Closes go-vikunja/vikunja#2392
2026-03-23 17:34:56 +00:00
kolaente 8538b4c885 test: add failing tests for quote-escaped task text parsing 2026-03-23 17:34:56 +00:00
renovate[bot] 36bd716e04 chore(deps): update dev-dependencies 2026-03-23 16:33:59 +00:00
MidoriKurage 4dd18e379e fix(frontend): origUrlToCheck references the same object as urlToCheck
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.
2026-03-23 15:43:23 +00:00
kolaente 1d45b385a5
fix(deps): update flatted to 3.4.2 to fix prototype pollution vulnerability 2026-03-23 12:53:13 +01:00
renovate[bot] 8bf450b98f chore(deps): update dependency caniuse-lite to v1.0.30001781 2026-03-23 10:28:55 +00:00
Frederick [Bot] 1ebe913181 chore(i18n): update translations via Crowdin 2026-03-23 01:19:01 +00:00
Claude cb81cf1aa8 refactor: reorganize quick add magic into focused modules
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
2026-03-22 20:47:10 +00:00
MidoriKurage c760a9bf72 fix(caldav): Replace href with pathname from parseURL for api base
`parseURL` only return `href` for special protocols. CalDAV api base
will always be root path. Use `pathname` which will not be undefined.
2026-03-22 14:30:38 +00:00
Claude 0085772b63 fix: include kanban bucket move permission in tasks preset
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
2026-03-22 14:24:23 +00:00
Claude 652eb9bba3 fix: remove small class from preset label
https://claude.ai/code/session_01QDWqXJmjriYoAcvMD43vmx
2026-03-22 14:24:23 +00:00
Claude 68097cf700 feat: add quick presets for API token permission selection
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
2026-03-22 14:24:23 +00:00
renovate[bot] 79f807f4c2 chore(deps): update dependency rollup to v4.60.0 2026-03-22 14:23:41 +00:00
Frederick [Bot] 1b246a0ff7 chore(i18n): update translations via Crowdin 2026-03-21 01:09:32 +00:00
kolaente b365be1881
chore: v2.2.0 release preparations 2026-03-20 13:40:18 +01:00
kolaente c81b0eb463 fix(attachments): sync kanban store and task ref on attachment changes
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.
2026-03-20 10:38:47 +01:00
kolaente ade91c92db refactor(attachments): remove global attachment store
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.
2026-03-20 10:38:47 +01:00
kolaente 2675bcb56c refactor(attachments): use local state instead of global attachment store
TaskDetailView now computes hasAttachments from the task ref and
handles the update:attachments emit from the Attachments component.
2026-03-20 10:38:47 +01:00