github wekan/wekan v9.47

4 hours ago

v9.47 2026-06-17 WeKan ® release

This release adds the following updates:

  • Developer test tooling: "Run ALL tests" now stops an existing dev server on port 3000 instead of aborting:
    rebuild-wekan.sh menu option 9 ("Run ALL tests") previously errored out with
    "Port 3000 is already in use" when a dev server was already running, forcing the
    user to stop it manually. It now detects and stops the existing Meteor dev server
    before starting its own. Thanks to xet7 and Claude. Details:
    • When port 3000 is busy, option 9 finds the existing Meteor dev server
      (pgrep -f 'meteor run --port 3000') and sends it a normal kill, which also
      tears down the node child it spawned.
    • It then polls the port for up to 30s, escalating to SIGKILL at the 15s mark
      and falling back to lsof -ti tcp:3000 (or fuser -k 3000/tcp) to catch
      anything still holding the port whose command line does not match.
    • Only if the port is still occupied after all that does it print an error and
      abort; otherwise it reports "Port 3000 is now free" and starts its own server.
  • Fix moving/copying a card silently failing with a 403 validation error:
    the move, copy, copy-many and convert-checklist-item card dialogs could leave a
    card in its original list instead of moving it. Thanks to xet7 and Claude.
    Details:
    • Root cause: the dialog's "Done" handler read the target board/swimlane/list by
      scraping the DOM <select> elements. The reactive boards() helper can
      transiently return [] while a board subscription re-resolves, leaving the
      board <select> momentarily option-less, so selectedIndex was -1 and the
      scraped boardId was undefined. card.move(undefined, …) then failed
      server-side with ValidationError: Not permitted. Untrusted code may only updateAsync documents by ID [403], and the card silently stayed put. This was
      a gap in the earlier dialog fix, which bound only the swimlane and list options
      to the live selection but left the board <select> on the (empty)
      last-confirmed option.
    • Fix: the Done handler now reads boardId/swimlaneId/listId from the
      dialog's live reactive selection (selectedBoardId/selectedSwimlaneId/
      selectedListId), which stays correct across re-renders, and the board
      <option selected> attribute is bound to the live selection in all four
      dialogs for UI consistency.
    • Test hardening: three Playwright/Node E2E tests that flaked under the
      all-parallel run (move-list-right, add-to-top/add-to-bottom, and the Node E2E
      second-session list-order check) now wait for the board subscription to
      populate before acting, instead of reading once after a fixed delay.
  • Developer test tooling: run all tests in parallel against a single dev server:
    rebuild-wekan.sh and rebuild-wekan.bat now run all tests in parallel
    against a single dev server, and fix the WebKit/Docker permission fallout.
    Thanks to xet7 and Claude. Details:
    • "Run ALL tests" (menu option 9) now starts one WeKan server on
      http://localhost:3000 (using .meteor/local) and runs every test job
      concurrently with a live, refreshing progress display: import regression,
      Node E2E, and Playwright Chromium + Firefox + WebKit all run against that one
      server, while the Mocha server-side suite runs at the same time in its own
      isolated Meteor build dir (.meteor/local-test, via METEOR_LOCAL_DIR) so the
      two Meteor builds never share .meteor/local. A per-job PASS/FAIL summary and
      per-job logs (../wekan-alltests-<job>.log) are written at the end. Previously
      these ran strictly one after another.
    • New menu option 16, "Test Playwright ALL browsers in parallel", runs
      Chromium + Firefox + WebKit at the same time against a server that is already
      running on :3000 (WebKit via the Playwright Docker image on Linux arm64, native
      elsewhere; the others run with --workers=3 on Windows).
    • Each Playwright browser now writes to its own test-results/<browser> output
      dir so parallel runs do not clobber each other's artifacts, and the WebKit
      Docker run executes as the host user (--user) so it no longer leaves
      root-owned files behind. A guard repairs an already root-owned test-results/
      that caused EACCES: permission denied, mkdir .../.playwright-artifacts-N.
  • Run ALL tests: start the :3000 server before Mocha so it boots fast again:
    the parallel "Run ALL tests" flow launched Mocha (in its own .meteor/local-test
    build) before the :3000 dev server, so two full Meteor builds competed for
    CPU/disk and the server took a long time to become ready — shown as a long line
    of dots during the readiness wait. Mocha and the import regression do not need
    the server, so they are now launched only after the server build is underway;
    the server builds alone and boots fast again, while they still run in parallel
    with the E2E and browser jobs. Applied to both rebuild-wekan.sh and
    rebuild-wekan.bat. Thanks to xet7 and Claude.
  • Fix #6380: login page missing username/password fields after upgrade:
    the password form is hidden by default in CSS and only revealed by JS when
    isPasswordLoginEnabled returns truthy; a slow/failed method call or a
    not-yet-rendered accounts form left the login without username and password
    fields. It now shows the form unless password login is explicitly disabled, and
    waits for the form element to appear before showing it. Thanks to xet7 and
    Claude.
  • Fix #6381: make the card "Mark as complete" toggle configurable, hidden by default:
    a new board setting allowsDueComplete (off by default) controls whether the
    "Mark as complete" toggle is shown on cards, with a checkbox in the board Card
    Settings popup to enable it per board. Thanks to xet7 and Claude.
  • Fix #6382: stop the client auto-creating thousands of empty swimlanes:
    getDefaultSwimline() inserted a swimlane whenever none was found, but on the
    client it runs inside reactive renders — for a board whose swimlanes were not
    yet loaded (e.g. the default subtasks board viewed via "All boards") every
    re-render inserted another empty swimlane (2008 in the report), freezing the
    browser. The default swimlane is now auto-created only on the server. Thanks to
    xet7 and Claude.
  • Move/Copy/Convert card dialogs: bind swimlane and list select to live selection:
    the swimlane and list <select> selected option in the move, copy, copy-many
    and convert-checklist-item card dialogs now follows the live selection instead
    of the last-confirmed option, so a Blaze reactive re-render can no longer
    silently revert the user's in-progress choice. Thanks to xet7 and Claude.
  • Playwright: probe browsers and skip ones that cannot launch on the host:
    the test runner now probes each browser and skips any that cannot launch (e.g.
    the bundled WebKit needs old system libraries that newer Linux arm64 distros
    like Ubuntu 26.04 no longer ship), removing false WebKit failures locally while
    still running every browser on CI. Override with WEKAN_PLAYWRIGHT_PROBE=1/0.
    Thanks to xet7 and Claude.
  • rebuild-wekan.sh: platform detection, Docker WebKit on Linux arm64, all browsers in ALL tests:
    detect OS/arch (Linux amd64/arm64, macOS arm64); run the WebKit Playwright specs
    via the official Playwright Docker image on Linux arm64 where the bundled WebKit
    cannot launch natively; and run Chromium, Firefox and WebKit in the "Run ALL
    tests" option. Thanks to xet7 and Claude.
  • rebuild-wekan.bat: Windows menu parity for building, running and testing WeKan:
    the Windows batch script now mirrors rebuild-wekan.sh's interactive menu so
    building, running and testing WeKan (Mocha, import regression, Node E2E and
    Playwright Chromium/Firefox/WebKit) works on Windows amd64/arm64 too. Thanks to
    xet7 and Claude.
  • Bumped form-data from 2.5.5 to 2.5.6:
    security fix for the CRLF-injection issue (CVE-2026-12143, GHSA-hmw2-7cc7-3qxx)
    where CR/LF/" in multipart field names and filenames were not escaped. It is a
    transitive dependency (pulled in via @google-cloud/storage); lockfile-only
    change. Thanks to Dependabot, xet7 and Claude.
  • Bumped launch-editor from 2.13.2 to 2.14.1:
    a dev-only dependency (used by webpack-dev-server / @rsdoctor/sdk, not in the
    production bundle); lockfile-only change. Thanks to Dependabot, xet7 and Claude.
  • Bumped docker/setup-buildx-action from 3 to 4:
    GitHub Actions workflow action update used by the Docker image build. Thanks to
    Dependabot, xet7 and Claude.
  • Bumped azure/setup-helm from 4 to 5:
    GitHub Actions workflow action update used by the Helm chart release workflow.
    Thanks to Dependabot, xet7 and Claude.
  • Bumped dompurify from 3.4.6 to 3.4.9:
    update of the HTML sanitizer used to sanitize card descriptions, comments and
    other rendered markdown (XSS protection). Thanks to Dependabot, xet7 and Claude.

and adds the following new features:

  • Added card dependency "Red Strings" / PI program board:
    visualize card-to-card dependencies as red, arrow-headed connection lines drawn on
    top of the board (for SAFe PI-planning program boards). A card now has a
    cardDependencies list edited from a new "Dependencies" section in the card detail
    (pick or remove other cards on the same board), and a board header toggle
    (showDependencies) renders an SVG overlay that draws a red curve from each card to
    each of its dependencies, following the live card positions on scroll/resize. The
    overlay is non-interactive (pointer-events: none) so cards stay clickable.
    Each dependency is now typed and customizable: a relation type
    (related-to, blocks, is-blocked-by, fixes, is-fixed-by — the type sets
    the arrow direction; related-to is undirected), a per-line color (any color,
    via a color picker, not just red) and an icon (FontAwesome). The card detail
    "Dependencies" section edits all three (relation type, color, icon picker), with a
    search-by-title picker to add one; a colored icon+count badge is shown on the
    minicard; and the board Filter sidebar can filter cards by dependency relation
    type
    . A REST API was added (tag Dependencies, documented in the OpenAPI
    docs and api.py): GET /api/boards/:boardId/dependencies,
    GET/POST /api/boards/:boardId/cards/:cardId/dependencies and
    PUT/DELETE /api/boards/:boardId/cards/:cardId/dependencies/:targetId, each
    accepting type/color/icon. Dependency lines can be exported (Board
    Settings → Export → Dependencies / JSON and / SVG; the SVG is a standalone,
    round-trippable diagram) and imported (All Boards → New → Import →
    Dependencies (JSON/SVG)) into a chosen board, matching cards by id, then card
    number, then title. Importing a Jira board now maps Jira issuelinks
    best-effort to dependency relations. Card dependencies and the board's
    showDependencies toggle are preserved through card/board copy and WeKan
    board export/import/migrate (target ids are remapped, dangling ones dropped), and
    a card moved to another board drops its now cross-board dependencies and
    cleans inbound references. Covered by tests
    (Part 1,
    Part 2,
    Part 3):
    e2e specs 27-red-strings (overlay, toggle, typed lines, minicard badge,
    copyCard preservation, import matching) and 28-dependencies-rest (REST CRUD +
    schema validation), plus mocha unit tests for the metadata helpers, the REST
    OpenAPI annotations, the filter selector, the cross-board move cleanup and the
    Jira issue-link mapping.
    Fixed editing an existing dependency from the card detail throwing a client
    403

    ("Untrusted code may only updateAsync documents by ID") — changing a relation's
    type/color/icon or removing it now rewrites the cardDependencies array and
    updates by _id instead of using a forbidden positional-$ selector update, and
    fixed the dependency icon picker not applying the chosen
    icon

    (the popup now edits the source card, not the dependency row), with an e2e test
    for editing a dependency's type/color/icon.
    Added a piplanning.io / Kendis / Miro-style drag-to-connect
    (Part 1,
    Part 2):
    when the overlay is on, each minicard shows a small connect handle (right
    edge, on hover) — drag it onto another card to create a dependency (a dashed
    guide line follows the cursor) — and a connection line is clickable to
    change its type/color/icon or delete it. It is not a mode: cards stay
    clickable and the rest of the overlay is click-through.
    The Dependencies (JSON/SVG) importer now also best-effort maps Miro REST
    API data (items + connectors, resolved to card titles; "block"/"fix" captions →
    relation type); Kendis/piplanning.io (and GitHub/GitLab) have no public
    dependency format, so a generic { "lines": [...] } JSON interchange is
    documented for them. Documented in
    Features/RedStrings.
    Fixes #3392. Thanks to CodeFreezr, dbt4u, helioguardabaxo, xet7 and Claude.
  • Added an Admin Panel "Shared templates" view grouped by Organization / Team / email
    Domain
    :
    a new admin-only "Shared templates" tab under Admin Panel → People lists users'
    shareable template boards, grouped by Organization, Team or email Domain. The three
    scope checkboxes are live view filters (default unchecked); checking one or more shows
    the matching groups, and only users whose Templates board is non-empty are listed. A new
    admin-only adminSharedTemplates method enumerates each user's linked template boards
    (the cardType-linkedBoard cards in their Board Templates swimlane) and returns them with
    the user's orgs/teams/email domains; the boards are shown as links into each template
    board. Covered by an e2e suite (tests/playwright/specs/26-shared-templates.e2e.js).
    Documented in
    Features/Templates.
    Fixes #3313. Thanks to xet7 and Claude.

and fixes the following bugs:

  • Fixed duplicate MONGO_URL environment variable generated by the Helm chart,
    which made helm install/upgrade fail with duplicate entries for key [name="MONGO_URL"]
    when the default env list (which already includes MONGO_URL) was used. The chart now
    emits its computed MONGO_URL only when one is not already provided via env or secretEnv.
    Fixes #6289. Thanks to the reporter, xet7 and Claude.
  • Fixed GFM strikethrough (~~text~~) no longer rendering in card descriptions:
    markdown-it renders ~~text~~ to <s>…</s>, but the DOMPurify allow-list did not
    include s/del/strike, so the sanitizer stripped the tag (keeping the bare text).
    Those inline tags are now allowed in both DOMPurify configs. Fixes #6008. Thanks to
    Buo-ren Lin, xet7 and Claude.
  • Fixed the release pipeline's OpenAPI docs generator crashing on template-literal route
    paths
    ,
    which failed the GitHub Actions "release-all" bump job (AttributeError: 'NoneType' object has no attribute 'rstrip') when a REST route is registered with a backtick path
    such as `/api/boards/:boardId/export/${format}`. The generator now resolves such
    paths (a ${identifier} becomes a {identifier} path parameter) and skips any route
    whose path cannot be resolved statically instead of aborting the whole release. Thanks
    to xet7 and Claude.
  • Fixed the Member Settings "Change Avatar" entry rendering in a different (uppercase-looking)
    style than the other menu items
    :
    its label was mis-nested inside the <i class="fa fa-picture-o"> icon element instead of
    being a sibling of it, so it inherited the FontAwesome icon font styling. The label now sits
    directly under the menu link like every other entry. Thanks to xet7 and Claude.
  • Hardened the reactive DataCache teardown to re-check for dependents before stopping a
    still-used entry
    :
    the 60s teardown timeout could stop the computation and delete a value that a dependent
    re-attached to during the window, surfacing as a transient undefined (a contributor to the
    "Board not found" flicker). Thanks to xet7 and Claude.
  • Fixed board export error responses returning HTTP 200 with an empty body:
    the export endpoints passed a bare number to sendJsonResult, which treats its argument as an
    options object, so 404/400/403/auth failures returned 200 with no body. They now return the
    correct status code and a JSON error body. Thanks to xet7 and Claude.
  • Fixed the board create/delete REST handlers masking errors as success:
    POST /api/boards and DELETE /api/boards/:boardId caught errors and returned code: 200
    with the error as data; they now report the real status code (so e.g. an unauthorized delete
    returns a 4xx). Thanks to xet7 and Claude.
  • Hardened board import against out-of-range swimlane/card colors:
    like the earlier board-color fix, a card or swimlane color is now applied only when it is a
    recognized color value, so a foreign/old export carrying an unknown color can no longer fail
    collection2 validation and abort the import. Thanks to xet7 and Claude.
  • Fixed the GitHub Actions Playwright E2E workflow so the Firefox and WebKit
    browsers can actually run
    (Firefox/WebKit,
    mongosh):
    the test step now sets WEKAN_PLAYWRIGHT_ALL=1 (so
    --project=firefox/webkit resolve instead of failing with "Project not
    found"), WebKit was added to the CI matrix (Playwright's bundled WebKit runs
    headless on the Linux runner), and mongosh is now installed in the Playwright
    and Puppeteer-regression jobs (the e2e DB helpers shell out to it, which was
    failing with spawnSync mongosh ENOENT). npm run test:playwright:all got the
    same WEKAN_PLAYWRIGHT_ALL=1 fix. Thanks to xet7 and Claude.
  • Translated the remaining untranslated English strings in the Finnish
    translation

    (fi.i18n.json) — the Shared Templates, card-dependency ("Red Strings") and
    dependency import/export strings — using the existing Finnish terminology.
    Thanks to xet7 and Claude.
    • Fix flaky Playwright card/board tests under the parallel run:
      the new 3-browser parallel run surfaced three load-induced (not product)
      failures that took DOM snapshots before the UI had settled. Thanks to xet7 and
      Claude. Details:
    • 03-cards-operations "move does not create duplicate cards" read the card
      titles immediately after the move and could catch the card mid-flight
      (already removed from the source list, not yet rendered in the target). It
      now waits for the card to be visible in the target list and gone from the
      source list before snapshotting.
    • 03-cards-operations "add-to-bottom places the card last" polls until the
      reactive re-sort places the new card last, since submitNewCard only waits
      for the card to exist, not for its final sort position.
    • helpers/auth.js openBoard now retries up to 5 times at 20s each so the
      slowest browser (WebKit) survives the contention of the 3-browser parallel
      run against one shared dev server, instead of failing in test setup.
  • Build scripts: At tests option 9, run option 2 build if .build or node_modules missing.
    Thanks to xet7 and Claude.

Thanks to above GitHub users for their contributions and translators for their translations.

Don't miss a new wekan release

NewReleases is sending notifications on new releases.