Commit Graph

13805 Commits

Author SHA1 Message Date
kolaente d67c586c9b feat(magefile): detect indirect api translation key references
The api translation scanner only looked at literal arguments to i18n.T /
i18n.TP, so keys passed via a variable (e.g. the time.since_* keys stored
in a struct slice in pkg/utils/humanize_duration.go and looked up via
chunk.key) were invisible and had to be hard-coded in an allowlist of
dynamic prefixes.

Mirror the frontend scanner: collect every dotted string literal in the
Go source as a "usage hint" and treat any literal that matches a known
translation key as used. This automatically picks up the time.since_*
case and removes the need for the apiDynamicKeyPrefixes allowlist.
2026-04-23 13:30:51 +02:00
kolaente 1d637a4ac6 refactor(magefile): consolidate api+frontend translation checks into one task
Previously the PR introduced a separate `check:frontendTranslations` mage
task and a second CI job. Merge both into the existing `check:translations`
task and a single CI job. Also rename internal references from "backend" to
"api" to match the project convention (Vikunja's Go server is the api, not
the backend).
2026-04-23 13:30:51 +02:00
kolaente edd83f5e92 ci: run frontend translation check as a hard failure
Add a frontend-check-translations job that runs the new
check:frontendTranslations mage task. Like the existing
api-check-translations job, failures hard-fail CI. This makes
reviewers catch dead keys and missing $t() wiring up front instead of
having to flag them manually in pull request review.
2026-04-23 13:30:51 +02:00
kolaente d2ba697686 chore(i18n): remove unused frontend translation keys
Remove 47 keys from frontend/src/i18n/lang/en.json that are not
referenced by any $t / t / i18n.t / i18n.global.t / tc / <i18n-t>
call site, nor by any stored-as-literal dynamic lookup pattern.

The keys fall into a few broad groups: leftover attribute labels on
filter and label models, dropped editor toolbar entries, unused
password/password-confirmation copy, and a handful of stale admin and
migration strings. The sibling translation files will be reconciled on
the next Crowdin sync.
2026-04-23 13:30:51 +02:00
kolaente 1f871d4dbd chore(i18n): remove unused backend translation keys
Remove five keys from pkg/i18n/lang/en.json that are no longer
referenced by any i18n.T / i18n.TP call. These surfaced once the
translation check started reporting dead keys. The sibling translation
files will be reconciled on the next Crowdin sync.

Removed keys:
- notifications.task.comment.mentioned_message
- notifications.task.mentioned.message
- notifications.common.actions.assigned_you
- notifications.common.actions.assigned_themselves
- notifications.common.actions.assigned_user
2026-04-23 13:30:51 +02:00
kolaente 138a545523 fix(notifications): pass lang to overdue reminder translation
The call to i18n.T for notifications.task.overdue.overdue was missing
its first positional argument, so the translation key was being passed
as the language code. This surfaced as a "dead key" once the
translation check learned to look for unused entries. Fix the call so
the reminder line is properly localised.
2026-04-23 13:30:51 +02:00
kolaente 0035be3c12 feat(magefile): bidirectional translation key validation
Extend the existing check:translations task so it now also reports
"dead" keys - entries present in pkg/i18n/lang/en.json but never
referenced by any i18n.T / i18n.TP call. Dynamic references (where
the key is a runtime value, e.g. from a struct field) are handled via
an allowlist of prefixes so they don't false-positive.

Add a new check:frontend-translations task that performs the same
bidirectional check against frontend/src/i18n/lang/en.json by scanning
.vue / .ts / .js files for $t, t, i18n.t, i18n.global.t, tc, $tc calls
and <i18n-t keypath="...">. Template literals with ${...} interpolation
contribute a usage prefix instead of a single key. String literals that
exactly match a known translation key (or template-literal prefixes
assigned to a variable) are also treated as usage hints, so keys stored
in arrays or built up programmatically aren't flagged as dead.

Register the new task in Check.All so `mage check` covers both.
2026-04-23 13:30:51 +02:00
Dávid Takács-Tolnai 5c7d2a5e7a fix(desktop): drop redundant zoom clamp
Chromium already caps zoom levels internally, so the manual [-7, +7]
clamp was redundant. Removes the constants and clamping logic while
keeping the before-input-event approach intact for persistence support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 10:32:53 +00:00
Dávid Takács-Tolnai 82a4f1f0d2 fix(desktop): support Ctrl and mouse-wheel zoom shortcuts
Electron does not register zoom shortcuts by default, so the desktop app
had no way to scale the UI. Register Ctrl+Plus, Ctrl+Minus and Ctrl+0
via webContents.before-input-event, and Ctrl+scroll via the zoom-changed
event.

The zoom level is clamped to [-7, +7] (Chromium's range, roughly 28% to
358%) and persisted to zoom.json in app.getPath('userData'), so the
chosen level survives restarts. Restored zoom is re-applied on every
did-finish-load, since Electron resets zoom across page reloads.

Fixes #2623
2026-04-22 10:32:53 +00:00
renovate[bot] 71c2e01366 chore(deps): update dependency caniuse-lite to v1.0.30001790 2026-04-22 10:18:08 +00:00
renovate[bot] 49ac0348e4 chore(deps): update dev-dependencies 2026-04-22 06:31:37 +00:00
Frederick [Bot] 413e3dec1c chore(i18n): update translations via Crowdin 2026-04-22 01:28:34 +00:00
renovate[bot] 0b2b5b580d chore(deps): update dev-dependencies 2026-04-21 18:38:21 +00:00
kolaente 2829a851df feat(a11y): associate errors with inputs in FormInput and FormSelect
Wire aria-invalid, aria-describedby and role=alert on the form
primitive components so errors raised directly on FormInput or
FormSelect are announced by assistive tech and programmatically
linked to the control.
2026-04-21 11:44:36 +00:00
kolaente fd1a329f5d feat(a11y): add descriptive labels to task checkboxes
Adds aria-label='Mark {task} as done' to task checkboxes so
screen readers can distinguish between them. Passes ariaLabel
prop through FancyCheckbox → BaseCheckbox → input.

Fixes WCAG 2.4.6 (Headings and Labels).
2026-04-21 11:44:36 +00:00
kolaente 6f85a7fb6b feat(a11y): fix heading hierarchy across pages
- Home: greeting H2 → H1 (page needs a top-level heading)
- Task detail: task ID H1 → span (only title should be H1)
- Task detail: H6 breadcrumb → nav element
- App header: project title H1 → span (avoids duplicate H1)

Fixes WCAG 1.3.1 (Info and Relationships) and 2.4.6 (Headings).
2026-04-21 11:44:36 +00:00
kolaente c1f74ae9dc feat(a11y): add labels to color picker and sort select
Adds aria-label to the color input and sort select elements
so screen readers announce their purpose.

Fixes WCAG 3.3.2 (Labels or Instructions).
2026-04-21 11:44:36 +00:00
kolaente 4618f3491b feat(a11y): associate form errors with input fields
Adds aria-invalid, aria-describedby, and role='alert' to error
messages in FormField and Password components so screen readers
announce validation errors.

Fixes WCAG 3.3.1 (Error Identification).
2026-04-21 11:44:36 +00:00
kolaente a0d0379e95 feat(a11y): fix logo link accessible name to include 'Vikunja'
Changes aria-label from 'Overview' to 'Vikunja home' so the
accessible name includes the visible text.

Fixes WCAG 2.5.3 (Label in Name).
2026-04-21 11:44:36 +00:00
kolaente a34c247611 feat(a11y): use autocomplete='new-password' on register form
Adds autocomplete prop to Password component (defaults to
'current-password'). Register page passes 'new-password' so
password managers offer to generate a strong password.

Fixes WCAG 1.3.5 (Identify Input Purpose).
2026-04-21 11:44:36 +00:00
kolaente 21b7ae3f9f feat(a11y): add accessible names to modal dialogs
Passes aria-label to the <dialog> element via attribute inheritance
so screen readers announce the dialog's purpose.

Fixes WCAG 4.1.2 (Name, Role, Value).
2026-04-21 11:44:36 +00:00
kolaente 40ff558540 feat(a11y): add aria-live region to toast notifications
Adds role='status' and aria-live='polite' to the notification
container so screen readers announce status messages.

Fixes WCAG 4.1.3 (Status Messages).
2026-04-21 11:44:36 +00:00
kolaente 11ffb530be feat(a11y): add accessible names to icon-only buttons
Adds aria-label to sidebar toggle, mobile overlay, banner close,
modal close, quick actions close, task detail close, and dropdown
trigger buttons. Adds triggerLabel prop to Dropdown component.

Fixes WCAG 4.1.2 (Name, Role, Value).
2026-04-21 11:44:36 +00:00
kolaente 732b65ba7c feat(a11y): add skip navigation link and main landmark on auth pages
Adds a visually-hidden skip-to-content link as the first focusable
element. Adds id='main-content' to the <main> element. Changes
<section> to <main> on auth pages for proper landmark navigation.

Fixes WCAG 2.4.1 (Bypass Blocks).
2026-04-21 11:44:36 +00:00
kolaente eb441f8b0c feat(a11y): add i18n keys for accessibility labels 2026-04-21 11:44:36 +00:00
renovate[bot] 9d25864b25 chore(deps): pin dependency otplib to 12.0.1 2026-04-21 11:14:41 +00:00
kolaente b90e67d7ca test(e2e): await DELETE in caldav token revoke test to avoid race 2026-04-21 10:50:09 +00:00
kolaente be28ec70d8 test(e2e): await DELETE in session revoke test to avoid race 2026-04-21 10:50:09 +00:00
kolaente c0101afb59 test(e2e): widen recurrence due-date tolerance to 5s
CI shard 4 hit a ~996ms skew between the JS-constructed originalDue and
the backend's advanced due date, enough to bust the <500ms precision
bound. Bump precision to -4 (<5s) — still tight enough to confirm the
regeneration advanced by ~1 day, loose enough to absorb sub-second
round-tripping through Date → ISO → Go time.Time → JSON.
2026-04-21 10:50:09 +00:00
kolaente c3b86b2102 test(e2e): cover link share permission tiers 2026-04-21 10:50:09 +00:00
kolaente 17e0dde7d3 test(e2e): cover link share password protection 2026-04-21 10:50:09 +00:00
kolaente 19d3b9c4bb test(e2e): cover team share revocation 2026-04-21 10:50:09 +00:00
kolaente f20267164f test(e2e): cover team READ_WRITE permission 2026-04-21 10:50:09 +00:00
kolaente be225fd4d3 test(e2e): cover team READ permission boundary 2026-04-21 10:50:09 +00:00
kolaente 01b71577d7 test(e2e): add TeamProjectFactory 2026-04-21 10:50:09 +00:00
kolaente 268c5daf8b test(e2e): drop unused authenticatedPage from recurrence beforeEach 2026-04-21 10:50:09 +00:00
kolaente 37d7f90acf test(e2e): cover monthly repeat mode UI 2026-04-21 10:50:09 +00:00
kolaente 637d810ff7 test(e2e): assert recurring task regenerates on complete 2026-04-21 10:50:09 +00:00
kolaente c93f644363 test(e2e): cover recurrence preset buttons 2026-04-21 10:50:09 +00:00
kolaente f2eee5d8a1 test(e2e): assert readers cannot delete attachments 2026-04-21 10:50:09 +00:00
kolaente 05432d3993 test(e2e): cover attachment deletion 2026-04-21 10:50:09 +00:00
kolaente db634093e0 test(e2e): drop unused authenticatedPage from webhooks beforeEach 2026-04-21 10:50:09 +00:00
kolaente 425889b879 test(e2e): create and delete a webhook 2026-04-21 10:50:09 +00:00
kolaente 5a93149849 test(e2e): require at least one webhook event 2026-04-21 10:50:09 +00:00
kolaente 2f2aafadfd test(e2e): validate webhook target url 2026-04-21 10:50:09 +00:00
kolaente 8bcdc314b1 test(e2e): cover data export request flow 2026-04-21 10:50:09 +00:00
kolaente a9f8fbaba8 test(e2e): cover scheduled deletion cancel flow 2026-04-21 10:50:09 +00:00
kolaente 2a5e4f2b84 test(e2e): cover account deletion request flow 2026-04-21 10:50:09 +00:00
kolaente 0902c009f6 test(e2e): assert current session has no delete control 2026-04-21 10:50:09 +00:00
kolaente 76055b622b test(e2e): assert session delete breaks refresh 2026-04-21 10:50:09 +00:00