Commit Graph

13025 Commits

Author SHA1 Message Date
kolaente
f516bbe560 test: update event assertions to work with deferred dispatch
Tests that call model methods directly now call events.DispatchPending
before asserting event dispatch.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
6ed684d708 fix(events): dispatch pending events in migration and export handlers
Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
924eef58d1 fix(events): dispatch pending events in CalDAV handlers after commit
CalDAV handlers manage their own database sessions. Now that model
methods use DispatchOnCommit, the CalDAV handlers must call
DispatchPending after commit and CleanupPending on rollback.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
1f363dbd43 fix(events): defer event dispatch for user creation and task positions
Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
8afbdf2deb fix(events): defer event dispatch for team operations
Convert events.Dispatch to events.DispatchOnCommit in team and team
member CRUD. Also removes premature s.Commit() from TeamMember.Delete
since the handler manages the transaction lifecycle.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
dd7f7de518 fix(events): defer event dispatch for project operations
Convert events.Dispatch to events.DispatchOnCommit in project CRUD,
project-user sharing, and project-team sharing.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
fe459c9297 fix(events): defer event dispatch for task sub-entities
Convert events.Dispatch to events.DispatchOnCommit in task assignees,
comments, attachments, relations, and kanban bucket operations.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
3eb289262f fix(events): defer task event dispatch until after transaction commit
Convert events.Dispatch to events.DispatchOnCommit in Task.Create,
updateSingleTask, Task.Delete, and triggerTaskUpdatedEventForTaskID.
Events are now dispatched by the handler after s.Commit(), ensuring
webhook listeners see committed data.

Fixes #2315
2026-03-03 12:46:34 +01:00
kolaente
217a481162 feat(handlers): dispatch pending events after transaction commit
All generic CRUD handlers now call events.DispatchPending(s) after
s.Commit() and events.CleanupPending(s) on rollback paths. This is
preparation for switching model methods from events.Dispatch to
events.DispatchOnCommit.

Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
564573bdd5 feat(events): add DispatchOnCommit/DispatchPending for deferred event dispatch
Events dispatched inside model methods run before the transaction commits,
causing listeners (especially webhooks) that open new sessions to read
stale data. These new functions allow accumulating events during a
transaction and dispatching them only after commit.

Refs #2315
2026-03-03 12:46:34 +01:00
renovate[bot]
9a4a2eb184 chore(deps): update dev-dependencies 2026-03-03 12:45:12 +01:00
Dominik Pschenitschni
e8a5631ffe feat(frontend): highlight overdue tasks consistently (#958) 2026-03-03 12:37:21 +01:00
Dominik Pschenitschni
0a9586e8d4 feat: use offical vite plugin for sentry (#873) 2026-03-03 12:30:49 +01:00
Dominik Pschenitschni
e1d1e7c848 feat: ensure forms submit on Enter (#959) 2026-03-03 12:28:45 +01:00
Dominik Pschenitschni
d94429d33c fix(caldav): parse timestamps in configured timezone 2026-03-03 12:18:48 +01:00
kolaente
0792b3d8b7 feat(release): update frontend package.json version on release
Closes #892
2026-03-03 11:49:04 +01:00
kolaente
958bd133fd fix(frontend): use mbs-2 utility class instead of scoped CSS
Replace the scoped .notification-actions rule with the project's
mbs-2 utility class for margin-block-start spacing.
2026-03-03 11:46:18 +01:00
kolaente
59b3dd32ac fix(frontend): use semantic class instead of targeting Tailwind utility
Replace .tw\:flex CSS selector with a .notification-actions class
in Notification.vue, as suggested in review.
2026-03-03 11:46:18 +01:00
kolaente
a08667b669 feat(frontend): upgrade Tailwind CSS from v3 to v4
- Replace tailwindcss v3 with tailwindcss v4 + @tailwindcss/vite plugin
- Create dedicated tailwind.css entry with granular imports (skip preflight)
- Use CSS-first config with prefix(tw) instead of JS config
- Switch from PostCSS plugin to Vite plugin for better performance
- Update class prefix from tw- (dash) to tw: (colon) in all Vue files
- Remove @tailwind directives from global.scss
- Delete tailwind.config.js (replaced by CSS directives)
- Update stylelint at-rules for v4 directives
2026-03-03 11:46:18 +01:00
Tink
a160048cc3 fix: update old kolaente.dev URLs to code.vikunja.io (#2342)
## Summary

- Updates all remaining `kolaente.dev` URLs in active code/config to
`code.vikunja.io`
- Updates Go Report Card badge to use current module path
`code.vikunja.io/api`
- Historical changelog references are intentionally left unchanged

Closes #655

## Files changed

- `config-raw.json` — language comment URL
- `README.md` — Go Report Card badge
- `pkg/routes/routes.go` — issue reference in comment
- `frontend/src/styles/custom-properties/colors.scss` — issue reference
in comment
- `frontend/src/helpers/time/createDateFromString.ts` — issue reference
in JSDoc
- `frontend/src/views/user/Login.vue` — issue reference in comment
- `frontend/histoire.config.ts` — PR reference in comment

---------

Co-authored-by: kolaente <k@knt.li>
2026-03-03 10:22:17 +00:00
kolaente
51f789bf5c fix(e2e): drain event handlers and stop browser between tests
Async event handlers (via Watermill) from the previous test can hold
SQLite connections, starving the next test's fixture setup PATCH request.

Three changes fix this:

1. Track in-flight event handler goroutines with a WaitGroup.
2. Call WaitForPendingHandlers() in the test endpoint before
   truncating/inserting data.
3. Navigate the browser to about:blank in fixture teardown to stop
   notification polling and other frontend requests between tests.
2026-03-03 10:41:19 +01:00
kolaente
39acdac531 fix(caldav): eliminate nested db session in CalDAV auth
checkUserCaldavTokens called user.GetCaldavTokens which creates its own
db.NewSession(), while the caller (BasicAuth) already holds an open
session. With SQLite this caused a deadlock because the second session
blocks on the write lock held by the first session in the same goroutine.

Add GetCaldavTokensWithSession that accepts an existing session and use
it from checkUserCaldavTokens.
2026-03-03 10:41:19 +01:00
kolaente
530973c475 fix(auth): make SameSite=None conditional on HTTPS for refresh cookie
SameSite=None requires Secure=true per browser spec. When running over
plain HTTP (local dev, e2e tests), browsers reject or downgrade the
cookie, breaking session refresh. Fall back to SameSite=Lax for HTTP
while keeping SameSite=None for HTTPS (needed for the Electron desktop
app cross-origin scenario).
2026-03-03 10:41:19 +01:00
kolaente
98f2893ffe fix(db): use WAL mode for SQLite and temp file for ephemeral databases
Three SQLite connection issues are fixed:

1. The refactoring in 26c0f71 accidentally dropped _busy_timeout from
   the file-based SQLite connection string. Without it, concurrent
   transactions get instant SQLITE_BUSY errors instead of waiting.

2. _txlock=immediate forced ALL transactions (including reads) to
   acquire the write lock at BEGIN, serializing all database access.
   WAL mode makes this unnecessary: readers use snapshots and never
   block writers, so the SHARED-to-RESERVED deadlock cannot occur.

3. In-memory shared cache (file::memory:?cache=shared) uses table-level
   locking where _busy_timeout is ineffective (returns SQLITE_LOCKED,
   not SQLITE_BUSY) and concurrent connections deadlock. Replace with a
   temp file using WAL mode for proper concurrency.
2026-03-03 10:41:19 +01:00
kolaente
84d563c51b fix: add /tmp directory to Docker image to fix data export
Fixes #2222
2026-03-02 17:15:20 +01:00
kolaente
26c0f71b6c fix(db): use immediate txlock for SQLite instead of MaxOpenConns(1)
MaxOpenConns(1) caused Go-level deadlocks: when two goroutines needed
database connections concurrently, the second blocked forever waiting
for the single connection pool slot. This broke CI (sqlite web tests
timed out after 45min, e2e tests hung).

The actual "database is locked" errors were caused by SQLite's default
deferred transaction locking: two connections both acquire SHARED locks,
then deadlock when both try to promote to RESERVED for writing. SQLite
detects this instantly and returns SQLITE_BUSY, bypassing busy_timeout.

_txlock=immediate fixes this by acquiring the write lock at BEGIN time.
The second concurrent transaction waits (up to busy_timeout) instead of
deadlocking. Combined with WAL mode (concurrent readers + single writer),
this handles concurrency correctly without restricting the Go connection
pool.
2026-03-02 14:03:33 +01:00
kolaente
28f98a7a96 fix(auth): use SameSite=None for refresh token cookie to fix desktop app
SameSite=Strict prevents the browser from sending the HttpOnly refresh
token cookie in cross-origin contexts like the Electron desktop app,
where the page runs on localhost but the API is on a remote host. This
caused sessions to expire quickly because refresh requests never
included the cookie.

SameSite=None allows cross-origin sending while HttpOnly still prevents
JavaScript from reading the cookie value (XSS protection).

Resolves #2309
2026-03-02 13:54:10 +01:00
kolaente
79dbb40985 fix(db): prevent SQLite "database is locked" errors under concurrent writes
Configure SQLite connections with WAL journal mode, a 5-second busy
timeout, shared cache, and a max of 1 open connection. SQLite only
supports a single writer at a time, so without these settings concurrent
API requests (e.g. bulk task creation) would immediately fail with
"database is locked" instead of waiting and retrying.
2026-03-02 12:37:55 +01:00
kolaente
1ba6a74383 fix(nav): project drag handle position
Resolves https://community.vikunja.io/t/color-ordering-menu-overlapping/4289
2026-03-02 11:38:45 +01:00
Weijie Zhao
7297682cad fix: remove invalidateAvatarCache call that broke request deduplication (#2317)
When multiple avatar components mount with alternating sizes (e.g. 48
and 20), invalidateAvatarCache clears pending requests for ALL sizes of
the same user, causing each call to create a new HTTP request instead of
reusing the pending one.

I noticed this issue when I open a task with 20 comments, the avatar
requests make the service OOM.

<img width="733" height="551" alt="image"
src="https://github.com/user-attachments/assets/db45db31-294c-4363-ad27-38d454b5a6a2"
/>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-02 09:18:20 +01:00
Weijie Zhao
3ca4913fcb fix: use MinPositionSpacing threshold in calculateNewPositionForTask (#2320)
calculateNewPositionForTask only checked for lowestPosition == 0 before
triggering a full position recalculation. Extremely small position
values (e.g. 3.16e-285) passed this check, causing new tasks to get
meaningless positions via the index * 2^16 fallback, breaking sort
order.

Use the same < MinPositionSpacing threshold that
createPositionsForTasksInView and the position update handler already
use.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-02 09:14:38 +01:00
renovate[bot]
648605c066 chore(deps): update dependency @vue/tsconfig to v0.9.0 2026-03-02 09:06:20 +01:00
kolaente
8690332652 chore(deps): upgrade serialize-javascript to 7.0.3 2026-03-02 08:56:08 +01:00
kolaente
23d84e7811 fix(views): assign default position when creating new project views
When creating a new view without specifying a position, it defaulted to
0, causing it to always sort before all other views. Apply
calculateDefaultPosition to assign a unique position based on the view
ID, consistent with how projects, tasks, and buckets handle this.

Fixes go-vikunja/vikunja#2319
2026-03-02 08:35:35 +01:00
kolaente
a7e4a4f4af fix(migration): support space-separated date format in TickTick importer
Fixes https://github.com/go-vikunja/vikunja/issues/2324
2026-03-02 08:35:35 +01:00
kolaente
15aa773212 fix(frontend): add horizontal overflow handling to tables on mobile
Wraps all tables that were missing overflow handling in a
`has-horizontal-overflow` div to prevent horizontal overflow on mobile
viewports.

Affected components:
- Sessions.vue
- ApiTokens.vue
- ProjectSettingsWebhooks.vue
- LinkSharing.vue
- UserTeam.vue
- EditTeam.vue
- ProjectSettingsViews.vue

Fixes https://github.com/go-vikunja/vikunja/issues/2331
2026-03-02 08:35:35 +01:00
renovate[bot]
cb2647abbe chore(deps): update dev-dependencies 2026-03-02 08:26:16 +01:00
Frederick [Bot]
6076384b1f chore(i18n): update translations via Crowdin 2026-03-01 01:21:13 +00:00
kolaente
ec11643c24 chore: v2.1.0 release preparations v2.1.0 2026-02-27 15:00:53 +01:00
kolaente
412215ee2f fix(auth): correctly delete older password reset tokens in cron 2026-02-27 14:44:26 +01:00
kolaente
5c2195f9fc fix(auth): remove password reset token after use 2026-02-27 14:44:26 +01:00
Frederick [Bot]
059958b839 chore(i18n): update translations via Crowdin 2026-02-27 01:10:46 +00:00
kolaente
4cce6ed34c chore(deps): upgrade transitive minimatch from 10.2.1 to 10.2.3+ 2026-02-26 23:33:39 +01:00
kolaente
04590d959c chore(deps): upgrade transitive basic-ftp from 5.0.5 to 5.2.0
Add pnpm override to bump basic-ftp (transitive dependency via
puppeteer/get-uri) from 5.0.5 to 5.2.0.
2026-02-26 23:16:01 +01:00
kolaente
f2a4a40e28 chore(deps): override transitive rollup 2.x to use direct dependency version
Add pnpm override to force all transitive rollup dependencies to use
the direct dependency version (4.59.0), eliminating the old 2.79.2
pulled in by workbox-build.
2026-02-26 23:16:00 +01:00
renovate[bot]
a76ba87939 chore(deps): update dev-dependencies 2026-02-26 22:54:58 +01:00
kolaente
838254bb51 feat(multiselect): add green plus icon and always-visible hint to create option
Make the "create new" option in multiselect dropdowns visually distinct
from regular search results by adding a green plus icon and making the
hint text always visible instead of only on hover.
2026-02-26 17:37:11 +01:00
kolaente
1eccb0edb2 chore: add opensourcefinder verification 2026-02-26 17:12:26 +01:00
kolaente
c4ec7f032f feat(checklist): show green progress circle when all checkboxes are done 2026-02-26 17:07:03 +01:00
kolaente
80759831ec fix(editor): use overflow-wrap instead of word-break for text wrapping
word-break: break-all breaks text at any character, causing mid-word
breaks even when the word could fit on the next line. overflow-wrap:
break-word wraps at word boundaries first and only breaks mid-word
when a single word exceeds the container width.
2026-02-26 16:30:55 +01:00