The Delete and View buttons are in the rulesList child template's each,
but their handlers are on the parent rulesMain and used
Template.currentData() — which returned the PARENT data context, not the
clicked rule. So the rule id was null: deleting failed with
'Match error: Expected string, got null', and 'View rule' always opened
the first rule. Add explicit data-rule-id to the buttons and read it in
the handlers so both operate on the rule actually clicked.
rulesWorkflow.js used TAPi18n without importing it, so paletteLabel()
threw 'ReferenceError: TAPi18n is not defined' and the Add Rule click
handler aborted before saving — creating a rule in the Rules -> Workflow
view silently did nothing. Add the missing import.
Sandstorm username races.
- #2345: the Card Title Filter is now SAVED by every board trigger
builder (a trigger doc missing the field could never satisfy the
matcher's $in - those rules fired for nothing), SHOWN in the rule
details, and ENFORCED for archive/restore triggers by resolving the
title from the card when the activity lacks it; legacy field-less
triggers keep matching; the filter popup prefills its current value.
- #2674: rules created via POST/PUT /api/boards/:boardId/rules never
fired - missing matching fields are now normalized to '*' wildcards
and trigger/action types validated; the addMember/removeMember rule
actions no longer crash on unresolvable usernames or member-less
cards and their writes are awaited. New docs/API/Rules.md (endpoints,
matching fields, wildcard semantics, the exact two-rule
add-on-move-to/remove-on-move-from workflow), linked from REST-API.md;
api.py help now lists the rule commands with the same example.
- #574: Sandstorm unique-username generation probes case-insensitively
(anchored, regex-escaped) and retries the next number when a
concurrent insert wins the unique-index race, instead of aborting the
login hook with E11000.
Tests: tests/rulesCardTitleFilter.test.cjs (12),
tests/rulesApiTriggerNormalize.test.cjs (19),
tests/sandstormUsername.test.cjs (11) - positive and negative cases.
Thanks to InfoSec812, sfahrenholz, mitar and xet7.
- #6459: card More menu rendered empty (no Delete): the vendored jade
compiler's htmljs patch made isConstructedObject(Array) false, so
'label {{_ ...}}:' lines got their content array mis-assigned as tag
attributes and Blaze threw 'foreign objects in attributes' killing the
whole cardMorePopup. Also fixed the list More link input (nonexistent
rootUrl helper -> absoluteUrl).
- #6455: saving a card description never removed a pre-existing unsaved-
edits record, and the draft/description comparison mismatched on Markdown
hard-breaks and empty descriptions, re-creating a phantom draft on every
save. Save now clears the draft; both sides normalized the same way.
- #5547: comment drafts: the draft-saving escape handler had been disarmed
since 2019 (flag with no setter), so a comment being written was lost
when the card closed. Drafts are now saved continuously (debounced),
flushed on teardown, cleared on submit; text no longer visually vanishes
on outside clicks.
- #5282: attachment delete: guard against the doc being already evicted
from Minimongo ('Removed nonexistent document'), like the existing
comment/checklist guards.
- #6472: rules move card to top/bottom: fall back to the card's current
list when listName does not resolve (was a swallowed TypeError = rule
silently did nothing); wizard stored listTitle which the engine never
reads (listName); empty destination wrote sort +-Infinity; rules JSON/CSV
import now uses the rules.createRule method instead of client inserts
rejected into minimongo limbo, and defaults missing trigger matching
fields to '*'; empty boardId no longer overrides the real board; the
server-side orphaned-cards fallback in List.cards()/cardsUnfiltered()
now actually resolves its async swimlane lookup.
- #6465: desktop density back to WeKan 6.09: base font 14px and headings
22/18/16px (vw clamps resolved to 18/24px on desktop), All Boards
wrapper padding 10px/15px, card details docks to the right edge instead
of floating on top of its own card (still draggable), 20px canvas
padding instead of ~48px white borders, removed the force-all-card-text-
to-title-size rule, admin org/team table Select/Unselect-all header
links are compact icons and header cells may wrap, zoom pill no longer
cut off, one-click board settings cog in the board header.
- #6458#6466: snap: mongodb-control now checks mongod's exit status and
does an AVX pre-flight (MongoDB 5+ needs AVX; without it mongod SIGILLs)
instead of pinging a dead port forever behind a 502: it switches to a
completed FerretDB migration, or (re)runs the migration (AVX-free) with
a 3-attempt guard. Migration importers no longer fail the whole run on
>=10 per-item errors ('Avatars Errors' etc.), and a failed 3.x-source
migration keeps the copied FerretDB data + checkpoint and resumes next
start instead of deleting it and 'falling back' to a mongod 7 that
cannot open 3.x data files.
- #6467#6468: with FerretDB, calm Meteor's no-oplog polling storm
(METEOR_POLLING_THROTTLE_MS=2000, METEOR_POLLING_INTERVAL_MS=30000
defaults in the snap and bundle launcher; overridable). The FerretDB
fork gets filter pushdown, a sane pool size and less locking in its own
repo.
- Updated ChangeLog.
Thanks to xet7.
The rules move-card-to-top/bottom (on another board) and link-card-to-another-board
actions failed in two ways for boards the rule creator did not own:
- The action showed BLANK after creating the rule: the wizard inserted the
trigger/action/rule with three optimistic client Collection.insert() calls
that landed in minimongo limbo once the wizard subscription stopped (and the
client allow/deny rules rejected them outright for non-owner members). These
now create the rule through the server rules.createRule method, which keeps
the action's own destination boardId.
- Execution crashed with a generic Internal Server Error: the destination
swimlane fallback dereferenced ._id on a possibly-undefined swimlane titled
exactly Default, which does not exist when the destination board's default
swimlane was renamed, translated, or the board had no such swimlane.
Resolution now uses the board's real default swimlane and a Meteor-free
resolver (models/lib/ruleActionResolve.js) that returns empty string instead
of throwing. The same guard is applied to the createCard and linkCard actions.
Unit tested (positive + negative) in tests/ruleActionResolve.test.cjs.
Thanks to DarthKillian and xet7.
The workflow trigger/action palette rendered hardcoded English labels
regardless of the UI language. Palette entries now carry an i18n labelKey
translated at render time via TAPi18n.__, reusing existing rule keys where
they fit and adding new r-w-* keys for workflow-only labels. Also routed
the slot clear tooltip through the existing r-remove key.
Deleting a rule ran three separate client-side Collection.remove() calls
(Rules + Triggers + Actions). Each is gated by a per-collection allow() rule
that resolves the board from that document own boardId via
Boards.findOneAsync(doc.boardId). When a trigger/action document has no
resolvable boardId (legacy rules created before boardId was denormalised, or
docs not published to the client), the board resolves to null and
allowIsBoardAdmin returns false, so Meteor rejects the mutation with 403
"Access denied" and the delete fails even for a legitimate board admin.
Route rule deletion through a new server Meteor method rules.deleteRule, which
authorizes ONCE (active board admin or site admin) and removes the rule, its
trigger and its action server-side (bypassing the brittle client allow/deny).
The permission decision is extracted into the Meteor-free helper
models/lib/ruleDeletePermission.js and covered by
tests/ruleDeletePermission.test.cjs. No permission is loosened: only board
admins and site admins may delete, matching the board-admin gate used to
create a rule.
In the IFTTT-Rules "Move card to the board" and "Link card to the board" actions, the
board dropdown was empty for some users — the current board included — while colleagues
in the same company could pick boards normally. Root cause: the dropdown filtered the
(already access-scoped) client cache with `'members.userId': me`, i.e. it only kept boards
where the user has a *direct* member entry. A user who reaches a board through an
Organization, Team or email-domain share — but is not listed individually in
`board.members` — matched nothing, so the whole selector came up empty. The dropdown now
filters by the same visibility rule as `Boards.userBoards()` (public OR active member OR
active org OR active team OR active domain), so org/team/domain-shared boards appear too,
while archived boards, template containers, the user's templates board and internal helper
boards stay excluded.
Thanks to Augustin356 and xet7 !
Fixes#5698
The board-triggers JS listened on js-add-arc-trigger while the jade emits
js-add-arch-trigger, so the click handler never fired and the archive trigger
could not be added. Align the JS selector to the jade's class. Added a regression
test asserting every jade trigger class has a matching JS handler.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Board/card 'button' rules now denormalise their button type/label onto the
schema-backed rules document (via a board-admin-gated rules.createRule method)
and the header/card read them from there, because the schemaless triggers
collection's documents do not reach the client over the board subscription;
the boardRules publication and the rules-list editor read from it too. Also
warn (instead of silently creating an empty board) when a pasted WeKan export
has no swimlanes/lists/cards (a broken older export).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(Arabic and its variants, Persian/Farsi, Hebrew, Uyghur, Uzbek-Arabic and
Yiddish — the languages flagged `rtl: true` in `imports/i18n/languages.js`).
Previously only some pages flipped. The root `<html>` element now gets a
reactive `dir="rtl"`/`dir="ltr"` attribute that follows the chosen language, so
the whole UI mirrors at once. To make this work on every page rather than a
handful, all directional component CSS was converted to CSS logical properties
(`margin-left`→`margin-inline-start`, `left:`→`inset-inline-start:`,
`text-align: left`→`text-align: start`, `float: left`→`float: inline-start`,
and the mirror-image right/end variants) across 48 stylesheets, which flip
automatically with `dir`. Horizontal-centering rules using
`left: 50%` + `transform: translate(-50%, …)` were intentionally kept physical,
since those already center correctly in both directions. The calendar view also
renders RTL. Thanks to xet7 and Claude.
- Tests for the RTL UI. A fast, server-less `tests/rtl.test.js` (run with
`node tests/rtl.test.js`) checks that exactly the expected languages are
flagged `rtl: true`, that the direction helper maps each language to the right
`dir` value, that the root `<html>` and the client keep `dir` in sync, and —
as a regression guard — that component CSS keeps using logical properties
(no physical `margin-left`/`float: left`/bare `left:` offsets sneak back in).
A Playwright browser spec `tests/playwright/specs/18-rtl-layout.e2e.js` drives
the app in both English (LTR) and Arabic (RTL) and asserts, on the boards list,
board view, card details, my-cards / due-cards / global-search, the admin
settings page and the login page, that the direction is correct, the
translated text is visible, and leading-edge content (the boards menu, the
first board list) sits on the correct side. Thanks to xet7 and Claude.
- Fixed the "Meteor unit tests" CI job hanging until its 45-minute timeout. The
workflow set `TEST_WATCH: '0'`, but meteortesting:mocha computes
`testWatch: TEST_WATCH || …` and the string `'0'` is truthy in JavaScript, so
it turned on watch mode and the process never exited. Removing the env var lets
`meteor test --once` finish and exit with the correct status.
Thanks to xet7 and Claude !
Fixes#6136,
fixes#3376,
fixes#884
Convert all remaining BlazeComponent-based components to native Meteor
Template pattern: activities, comments, all rules actions/triggers,
swimlanes, users, gantt, import, and main utility components.