Compare commits

...
95 Commits
Author SHA1 Message Date
github-actions[bot] 9c51391a75 Bump versions for v9.83 2026-07-09 11:57:12 +00:00
Lauri Ojansivu 2ed13a1593 Updated ChangeLog. 2026-07-09 14:48:08 +03:00
Lauri Ojansivu ca50c9d1aa Updated ChangeLog. 2026-07-09 14:45:09 +03:00
Lauri Ojansivu 548d7b483e Updated ChangeLog. 2026-07-09 14:42:48 +03:00
Lauri Ojansivu 71bbc9f67e Updated ChangeLog. 2026-07-09 14:09:14 +03:00
Lauri Ojansivu 05fd6fd3a5 Fix #3624 swimlane REST regression: await the async board.swimlanes()
The swimlanes CRUD e2e test (23-rest-api-more.e2e.js:209) regressed on all
browsers. Root cause: on the server ReactiveCache.getSwimlanes is async, so
board.swimlanes() returns a Promise in the REST handler. The #3624 change read
board.swimlanes().map(s => s.sort); .map on a Promise throws, the insert never
ran, the error was swallowed by the handler's catch (returned as 200 with no
_id), and the test read .title off a null swimlane.

The earlier "move the require to a top-level import" commit was not the real
cause (the same module.exports import pattern works server-side, e.g.
ruleDeletePermission in rulesButton.js). The actual fix is to await
board.swimlanes() before mapping. This also means API-created swimlanes now get
a real max(existing sort)+1 sort — previously the un-awaited `.length` yielded
undefined, so they were stored with no sort at all, which is the #3624 symptom.

Verified: the swimlane test passed in every kept local run through
2026-07-09_02-38-07 and failed starting 09-52-25 (right after the #3624 change),
confirming the regression window; the tests/swimlaneSort.test.cjs unit test
still passes.
2026-07-09 14:09:14 +03:00
github-actions[bot] e8939bc1e6 Bump versions for v9.82 2026-07-09 08:13:59 +00:00
Lauri Ojansivu bc8d58011c Prepare v9.82 release 2026-07-09 11:08:40 +03:00
Lauri Ojansivu 0bf8cae81c Updated ChangeLog. 2026-07-09 10:43:25 +03:00
Lauri Ojansivu 984ec160da Fix Playwright CI failures from #3624 and #4236
Two e2e tests failed across Chromium/Firefox/WebKit after this release's changes:

- 23-rest-api-more.e2e.js:209 (swimlanes: create, get, edit, delete): the
  #3624 change referenced models/lib/swimlaneSort via a function-scoped
  require('/models/lib/swimlaneSort'); the new module was not reliably bundled/
  resolved that way, so POST /api/boards/:id/swimlanes threw, was caught, and
  returned an error object with no _id — the test then read title off a null
  swimlane. Import nextSwimlaneSort at the module top level, matching every
  other import in server/models/swimlanes.js, so it is statically bundled.

- 02-cards-open-view.e2e.js:93 (editing the card title does not break the card):
  #4236 intentionally made plain Enter insert a newline in the card title
  (consistent with the description), with Ctrl/Cmd+Enter saving. The CardPage
  page object still saved with plain Enter, so the title never persisted and the
  read timed out. Save with Control+Enter (sends ctrlKey on every platform,
  which the save handler accepts).

Server-side Mocha, import regression, and Node E2E jobs already passed; this
makes the Playwright jobs green too.
2026-07-09 10:26:03 +03:00
Lauri Ojansivu a2df80e64d Updated ChangeLog. 2026-07-09 10:09:58 +03:00
Lauri Ojansivu 3aaf8f9b61 Fix #6444: RTL — typing a card title no longer garbles other lists' minicard titles
In an RTL language (e.g. Arabic) the board root is dir="rtl". Both the minicard
title (a dir="auto" .viewer) and the add-card composer textarea are dir="auto"
but had no bidirectional isolation, so they shared the surrounding bidi context.
Typing a strong RTL character into one list's composer re-resolved that shared
context and visibly reflowed the displayed minicard titles of the other lists
(no underlying data change — it reverted on refresh).

Each minicard title and the composer textarea now use `unicode-bidi: isolate`,
making them self-contained bidirectional runs that cannot perturb one another.
The isolation is locked in (positive + negative) by tests/minicardBidiIsolation.test.cjs;
full browser RTL behavior is covered by tests/playwright/specs/18-rtl-layout.e2e.js.

Thanks to xet7.
2026-07-09 10:09:32 +03:00
Lauri Ojansivu 1dfc223ca0 Updated translations 2026-07-09 09:48:44 +03:00
Lauri Ojansivu 604cc455e0 Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu e85072a14a Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 1621f3784a Fix #5439: list scrollbar is now always visible on desktop and mobile browsers
List bodies used overflow-y:auto, so on platforms/browsers with overlay
scrollbars (macOS, iOS, Android, Firefox) the scrollbar auto-hid when idle and
there was no persistent affordance that a list is scrollable.

The list body now shows a scrollbar across all engines: overflow-y:scroll to
always reserve and show the track, ::-webkit-scrollbar width + thumb/track for
Chrome/Safari/Edge and mobile WebKit/Blink, scrollbar-width + scrollbar-color
for Firefox/Gecko (desktop and Android), and scrollbar-gutter:stable so content
does not shift. The cross-browser rules come from a Meteor-free builder
models/lib/scrollbarCss.js and are applied in client/components/lists/list.css;
both the builder contract and the applied CSS are unit tested (positive +
negative, including that no hide values sneak back in) in
tests/scrollbarCss.test.cjs.

Thanks to xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu ba6ad20a30 Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 3847157753 Fix #3185: copying a card (or template) now copies its subtasks' checklists
When a card was copied — including generating a card from a template — each
subtask was inserted as a bare card document. The parent card's checklists were
copied, but the subtasks' checklists (and their items) were never copied, so
the new card's subtasks came out empty.

Card.copy() now copies each subtask's checklists (via Checklist.copy, which also
copies the checklist items) onto the newly inserted subtask. The subtask copy
document is built by a Meteor-free helper models/lib/subtaskCopy.js
(buildCopiedSubtaskFields — re-homes the subtask under the new parent and onto
the destination board; subtaskCopyChildKinds declares 'checklists' must be
reproduced), unit tested (positive + negative) in tests/subtaskCopy.test.cjs.

Thanks to ramses345 and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 4e77133aca Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 77c696e37b Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu e3f17be14d Fix #3624: new_swimlane REST API appends the swimlane last (and accepts a sort)
POST /api/boards/:boardId/swimlanes set the new swimlane's sort to
board.swimlanes().length (a count). When the existing swimlanes' sort values
were not a contiguous 0..n-1 run (after deletions/reordering, or swimlanes
created top-first with decreasing sorts), the count collided with or preceded
existing sorts and the new swimlane appeared FIRST instead of last.

The endpoint now computes the sort with nextSwimlaneSort(): max(existing sort)+1
for a reliable append (0 on an empty board), and honors an optional explicit
`sort` in the request body (the enhancement the reporter asked for). The pure
logic lives in models/lib/swimlaneSort.js, unit tested (positive + negative) in
tests/swimlaneSort.test.cjs.

Thanks to tamasberesoebb and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 5ca4ebe09a Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 3117e419bb Fix #3606: activity feed no longer shows "edited/deleted comment undefined"
The activity feed rendered "edited comment undefined" / "deleted comment
undefined" for comment edits and deletions. The template passed the comment's
ID into the "%s" of activity-editComment / activity-deleteComment: on older
activities the id was absent (literally "undefined"), and a deleted comment's
CardComment document is already removed so it cannot be looked up live either.

The edit and delete activities now store the comment text (commentText), and a
new Activities.commentDisplayText() helper picks the stored text, else the live
comment text (edit case), else an empty string — so the feed never renders the
word "undefined". The template shows the (sanitized) comment text. The
text-selection logic is a Meteor-free helper models/lib/commentActivity.js,
unit tested (positive + negative) in tests/commentActivity.test.cjs.

Thanks to janchuelo and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 3eba4aa782 Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 127f1fb04e Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 14b4f5b5ed Fix #4249: filter by card title now works for renamed linked cards
Renaming a linked card (or linked-board card) wrote the new title only to the
linked target (via getRealId()/linkedId), leaving the linking card's OWN title
field stale. Filter-by-title queries each card document's own title field, so a
linked card silently dropped out of title filters after being renamed.

Card.setTitle() now also writes the linking card's own title (in addition to the
linked target), keeping it filterable while preserving the existing mirror
behavior. The set of documents to update is a Meteor-free helper
models/lib/linkedCardTitle.js (computeTitleUpdateTargets), unit tested
(positive + negative) in tests/linkedCardTitle.test.cjs.

Thanks to Ben0it-T and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu e6a4abd394 Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 25cdc4db0d Fix #4494: Creating a board from a template no longer breaks subtasks
Creating a board from a template copies the template board. The copy inherited
the template's subtasksDefaultBoardId / dateSettingsDefaultBoardId verbatim.
When those pointed at the template board itself, subtasks created on the NEW
board were dropped onto the TEMPLATE board, and the subtask card linked back
across boards to the parent.

Board.copy() now repoints any subtasks/date-settings default that referenced
the source board to the new copy, and clears the paired list id so it self-heals
to a list on the new board. Defaults that deliberately point at another (shared)
board are left untouched. The remap logic is a Meteor-free helper
models/lib/boardCopyDefaults.js, unit tested (positive + negative) in
tests/boardCopyDefaults.test.cjs.

Thanks to Xilef11 and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu c062d93d57 Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu e014d5c816 Fix #4394: Register / Forgot Password links stay hidden after a failed login
Security: with "Self Registration" and "Forgot Password" disabled in the Admin
Panel, the Register (.at-signup-link) and Forgot Password (.at-pwd-link) links
were hidden only by a one-shot jQuery .hide() in userFormsLayout.onRendered.
When a login failed (notably the LDAP "User not Found" path), useraccounts
re-rendered the form and recreated those link nodes without the inline
display:none, so the links reappeared and exposed registration / password-reset
flows that were meant to be off.

The disable state is now also reflected as a class on the stable <body>
ancestor (registration-disabled / forgotpwd-disabled) with matching CSS in
userForm.css. Because the class sits on <body>, the rule re-hides every copy of
the links that useraccounts recreates after a failed login, instead of relying
on a single inline style that the re-render dropped.

Thanks to Alsterdetektive1 and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 84ab805ec1 Fix #4055: add ISO week-number regression test (already correct in current code)
#4055 reported the calendar/date-badge week number was one week too high
(Mon-Sat) and two too high (Sunday) for 2021-10-25..31 (ISO week 43). That was
the old moment-based calculation. The current native, DST-safe
dateUtils.getISOWeek() computes these correctly (verified across a DST timezone).
Adds tests/isoWeek.test.cjs pinning the exact reported dates so the off-by-one/
two cannot silently return.

Thanks to marcungeschikts and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu a9a5ac7a07 Fix #4236: Enter adds a new line in the card title (consistent with description)
The card title textarea submitted on plain Enter (only Shift+Enter made a new
line), while the card description textarea and the shared inlinedForm insert a
new line on plain Enter and only save on Ctrl/Cmd+Enter. So Enter could not add
a new line in the title, an inconsistent experience.

The title keydown handler now uses a shared, Meteor-free rule isSubmitKey()
(models/lib/editorSubmitKey.js): submit ONLY on Enter together with Ctrl or Cmd;
plain Enter and Shift+Enter fall through to the textarea default (a new line).
This matches the description field exactly. Unit tested (positive + negative) in
tests/editorSubmitKey.test.cjs.

Thanks to listenerri and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 0119e62da5 Fix #4653: LDAP username with a hyphen no longer becomes a dot
With LDAP_UTF8_NAMES_SLUGIFY enabled, sync.js slugified the username with
limax(text, { separator: '.' }) to transliterate UTF-8 names. limax replaces
every run of non-alphanumeric characters — including hyphens — with the
separator, so an LDAP username like "p.parta-partb" was turned into
"p.parta.partb". The generated Wekan username no longer matched and the user
could not log in.

slug() now slugifies each hyphen-separated segment on its own and rejoins
them with '-', so hyphens (and existing dots) survive while UTF-8 characters
in each segment are still transliterated. The hyphen-preserving logic is a
Meteor/limax-free helper packages/wekan-ldap/server/usernameSlug.js
(slugifyPreservingHyphens, with the transliterate function injected), unit
tested (positive + negative) in tests/ldapUsernameSlug.test.cjs.

Thanks to RowhamD and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 284d4b25ea Updated ChangeLog. 2026-07-09 09:45:53 +03:00
Lauri Ojansivu 75df523ef0 Fix #4946: Calendar week numbers now respect the defined start day of week
In the board Calendar view the week-number column was numbered from Sunday
regardless of the user's "start day of week" setting: setting Monday moved
the grid (via firstDay) but the week numbers still referred to Sunday-start
weeks. FullCalendar's default weekNumberCalculation is locale-based, so it
ignored firstDay.

The calendar now passes weekNumberCalculation that computes the number with
weekNumberByFirstDay(date, firstDay) from the same firstDay used to lay out
the grid, so the number matches the displayed week. The Meteor-free week math
lives in models/lib/weekStart.js and is unit tested (positive + negative,
including a case where Monday-start and Sunday-start must differ) in
tests/weekStart.test.cjs.

Thanks to helioguardabaxo and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu e5c844fca7 Fix #4881: Due this week / next week filter now respects the start day of week
The "Due this week" date filter selected the wrong week (it showed next
week's cards) and ignored the user's configured start day of week.

Root cause: relativeWeek() derived its window from startOf(now(), 'week'),
but the native dateUtils.startOf() has no 'week' case, so it returned the
date unchanged. The window therefore started at "today + startDayOfWeek"
(next week) instead of the beginning of the current week, and never took the
configured start weekday into account.

Fix:
- New Meteor-free helper models/lib/weekStart.js computes startOfWeek(),
  weekRange() and weekNumberByFirstDay() for an arbitrary start day of week
  (0=Sunday..6=Saturday, default Monday). Unit tested (positive + negative)
  in tests/weekStart.test.cjs, including a guard that "this week" must
  contain today.
- client/lib/filter.js relativeWeek() now uses weekRange(now(), weekStartDay,
  0|1) so "this week" and "next week" are the correct, non-overlapping
  Monday..Sunday (or configured) windows.
- The this/next-week buttons now toggle per week: clicking the active one
  clears it, clicking the other switches to it (the old code reset on either
  state, so you could not switch directly from this week to next week).

Thanks to mimZD and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 8a84707726 Fix #4978: Board background now updates when switching boards via favorites bar
Switching directly from one board to another using the favorites bar reused
the same boardBody template instance (currentBoard went A -> B, never null),
so boardBody.onRendered never fired again and the one-shot
Utils.setBackgroundImage() call never re-ran. The previous board's inline
background:url(...) on .board-wrapper stayed on screen. Switching via the
"all boards" list worked only because it destroys and re-creates boardBody.

Two-part fix:
- boardBody.onRendered now calls Utils.setBackgroundImage() inside a reactive
  this.autorun(), so it recomputes on every board switch (and background edit).
  It performs no DB writes, so there is no autorun write loop.
- setBackgroundImage() now clears any stale inline background when the new
  board has no image, instead of only ever setting one. The decision is a
  Meteor-free helper models/lib/boardBackground.js (computeBoardBackground),
  unit tested (positive + negative) in tests/boardBackground.test.cjs. Board
  color keeps being applied reactively via the .board-wrapper colorClass.

Thanks to dasarne and xet7.
2026-07-09 09:45:53 +03:00
Lauri Ojansivu 9f7eac158e Fix #5536: Automated rule can now move/link card to a different board
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.
2026-07-09 09:45:53 +03:00
github-actions[bot] 9b729b502e Bump versions for v9.81 2026-07-09 00:17:50 +00:00
Lauri Ojansivu cef965f73f Updated ChangeLog. 2026-07-09 03:08:00 +03:00
Lauri Ojansivu 43dd98f8a1 Translate remaining English strings in fi.i18n.json to Finnish
Translate the strings that were still in English (mostly keys added this
release: the Rules Workflow trigger/action palette, the relative-date
unit selector, the custom color-wheel label, the Activities hide toggle
and the changed-description activity), using the terminology already used
in the existing Finnish translations.
2026-07-09 02:30:16 +03:00
Lauri Ojansivu 2cd772fcf5 Updated translations. 2026-07-09 02:25:49 +03:00
Lauri Ojansivu eaa1d823de Updated ChangeLog. 2026-07-09 02:19:52 +03:00
Lauri Ojansivu 1a41c72c21 Update CHANGELOG commit links to post-rebase hashes 2026-07-09 02:17:01 +03:00
Lauri Ojansivu 7943a17432 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu d41e17d6a0 Fix #5351: auto-add users to organizations matching their email domain on sign-up.
The Organization setting "Automatically add users with the domain name"
(org.orgAutoAddUsersWithDomainName) was never read at sign-up, so a user whose
email domain matched an organization was never added to it.

Add a pure helper models/lib/orgAutoAddByDomain.js (orgsToAutoAddForEmail) that
returns the ids of orgs whose configured domain exactly matches an email domain
(case-insensitive, exact — no subdomain, empty domain matches nothing), and wire
it into Accounts.onCreateUser so every non-admin sign-up path (password, LDAP,
invitation, new OIDC user) gains the matching org memberships using the same
{ orgId, orgDisplayName } shape used elsewhere, without duplicating existing
memberships. Add tests/orgAutoAddByDomain.test.cjs.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 4ec2cbcd5a Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 1ce2d8cc88 Fix #5369: Activities show/hide control is now a clear eye / eye-slash icon toggle.
Replace the counterintuitive unlabeled material toggle switch on the card
details Activities panel with an eye / eye-slash icon toggle: open eye means
activities are shown, crossed eye means they are hidden. Clicking flips the
state, the icon reflects the current visibility, and the tooltip states the
action (Show activities / Hide activities). The same eye pattern from the
login/register password-visibility toggle is reused for consistency.

For consistency the board sidebar Activities toggle (same showActivities
state) is switched from the check / empty-square icon to the same eye /
eye-slash icon toggle.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 8f76c7b2b0 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu b07c4d0a7b Feature #5394: sort the Link-card popup Cards dropdown alphabetically by title.
The "Link to this card" popup Cards pull-down previously listed cards in
board sort order, making a card hard to find on boards with many cards.
Sort it alphabetically by title (case-insensitive, locale/numeric aware)
via a small pure helper sortCardsByTitle, with unit tests. Thanks to xet7.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 5b43b7159e Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 7ce71dbb2e Feature #5396: edit Lists (title, color) via the REST API + api.py commands.
The REST endpoint PUT /api/boards/:boardId/lists/:listId already accepted
title, color, starred and wipLimit, but the color was stored unvalidated. It
now validates the color with normalizeListColor (a named palette color OR a
custom #rrggbb hex) and rejects an unknown color with a clear 400 instead of
silently storing None or hanging. The pure field/validation logic is extracted
to a Meteor-free helper models/lib/listApiUpdate.js so it is unit testable
without a running server (tests/listApiUpdate.test.cjs).

api.py gains two commands mirroring editcard/editcardcolor:
editlist BOARDID LISTID NEWLISTTITLE and
editlistcolor BOARDID LISTID COLOR, with usage lines in the help block.

Thanks to C0rn3j and xet7.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu d615e599f4 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu aad00cdba2 Fix #5442: outgoing webhooks now include the label name on add/remove label
Labels are embedded in the board document, not a separate collection, but the
Activities label() helper looked the label id up in the Cards collection and
always returned undefined. So the addedLabel/removedLabel webhook and
notification params never got a label value and the __label__ token in the
message text rendered as a bare, generic "label" with no name.

Resolve the label from the already-loaded board via getLabelById, and add a
pure labelDisplayName() helper (name -> color -> id fallback) so a nameless
label is shown by its color, matching the UI. Add a plain-Node unit test.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 07800da9af Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu da0d338e33 Fix #5482: adding/editing a card description fires the outgoing webhook
Card description changes did not create an activity, so no outgoing webhook
fired (unlike title/dueAt changes, whose Cards before.update hooks log an
activity). Log an a-changedDescription activity in the Cards before.update hook,
mirroring the title-change activity, so the existing Activities.after.insert
webhook hook fires. Fires on first-time set and later edits, not on no-op /
empty->empty saves. Pure descriptionChanged helper + tests, English i18n and
activity rendering.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu c3c091635d Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 8c499823cb Fix: the Rules Workflow view is now fully translatable via i18n.
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.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 1844425e8f Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 68dd14140f Fix: deleting a board rule no longer fails with "Access denied [403]"
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.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 1ba32f5269 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 30f36a7f31 Feature #5514: custom color-wheel (RGB/hex) picker with automatic readable text contrast.
Add a native color wheel (<input type="color">) alongside the existing fixed
named-color swatches in the color pickers for card labels, swimlanes, lists and
cards, so any #rrggbb color can be chosen. The schema color fields accept a
custom hex in addition to the named palette (via a validation that allows the
named values or a ^#[0-9a-fA-F]{6}$ hex), and normalizeListColor now passes hex
through, so existing named-color data keeps working. When a stored value is a
hex, elements apply an inline background-color instead of the card-details- /
swimlane- / list-header- / minicard- CSS class.

A new pure, Meteor-free helper models/lib/contrastColor.js computes a readable
text color from sRGB relative luminance (white on dark, black on light),
maps the named palette to hex, and validates/normalizes hex; it is applied as
an inline text color wherever a chosen color is a background behind text (label
chips, swimlane/list headers, minicard, card details header). Covered by
tests/contrastColor.test.cjs (20 assertions).
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 20b9c9ddd6 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 0e9aed5a4b Fix #5510: adding a board label via the REST API no longer errors/hangs
PUT /api/boards/:boardId/labels only wrote an HTTP response inside
`if (hasOwnProperty(req.body, "label"))` and read req.body.label.color/.name
unconditionally. Two consequences:

- A body without a `label` key fell through the `if` and NEVER sent a response,
  so the request hung until the client timed out (the reported "timeout").
- A body where `label` was a bare string (e.g. { "label": "labelName" }, the
  exact reported payload) produced name === undefined / color === undefined and
  pushed a schema-invalid label via Boards.direct, returning 200 for garbage.
- The catch returned { code: 200, data: error }, masking real failures as
  success (same anti-pattern already fixed for the board create/delete handlers).

The handler now returns a 404 for an unknown board, delegates input handling to
a new pure, Meteor-free helper models/lib/restLabel.js (buildBoardLabel), and
always sends a JSON response: 2xx for a well-formed create (documented contract
unchanged), 400 with a clear message for bad input, or the real error status in
the catch. buildBoardLabel accepts { label: { name, color } } (color defaulted
when absent, rejected when unknown) and, for convenience, a bare string taken as
the label name. Added tests/restLabel.test.cjs covering these cases.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 27d8468be0 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu d01526bbff Fix #5604: CSV export no longer crashes on boards with dangling references.
Exporter.buildCsv resolved each card list/swimlane/owner/member/assignee/label/
customField by id and read a property directly on the result of Array.find(),
which is undefined when the referenced document was deleted. Large/old boards
often contain such dangling references, so the read threw "Cannot read property
title of undefined" and crashed the whole CSV export request. Extracted the
per-card row builder into a pure, null-safe helper models/lib/exporterCsvRow.js
(unit-testable without Meteor) that emits a blank cell for a missing reference
while keeping identical output for well-formed cards. Added
tests/exporterCsvRow.test.cjs.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu ab3b48b334 Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu b0da9097c1 Fix #5656: Calendar view now honors the active board filters.
The Calendar view queried cards with only a board+date selector via
Board.cardsInInterval()/cardsDueInBetween() and ignored the active board
Filter (member / assignee / due-date / label / custom-field), so it showed
every card in the interval regardless of the sidebar filter, unlike the
Board / Lists / Swimlanes views.

Extract the calendar selector building into a pure, Meteor-free helper
(models/lib/calendarFilter.js) that ANDs the Filter selector into the
date-interval selector via combineWithFilter, so the Filter is always applied
and can never collide with the interval selectors top-level $or. The calendar
events() callback now passes Filter._getMongoSelector() when Filter.isActive(),
and the onRendered autorun reads Filter.isActive() so events are refetched when
the filter changes. Add tests/calendarFilter.test.cjs.

Thanks to kerier and xet7.
2026-07-09 02:14:07 +03:00
Lauri Ojansivu 158130cbfc Updated ChangeLog. 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 53328f40c6 Add unit selector (minute/hour/day/week/month) to the Rules relative-date action (#5621) 2026-07-09 02:14:07 +03:00
Lauri Ojansivu e7eeaf0b10 Add 'Count amount of tests by category' menu option to rebuild-wekan scripts 2026-07-09 02:14:07 +03:00
Lauri Ojansivu 609b07a8db Add 'Count amount of tests by category' menu option to rebuild-wekan scripts 2026-07-09 00:02:17 +03:00
Lauri Ojansivu 7545bb5506 Add #6442 fix to Upcoming WeKan release CHANGELOG section 2026-07-08 23:58:21 +03:00
Lauri Ojansivu 457713968c Fix #6442: All Boards custom drag order — drop now persists the reorder
Follow-up to #6439, which restored the drag preview but left the drop a
no-op: dragging a board on the All Boards page in "Custom (drag order)"
mode showed the dashed-border preview, but releasing it snapped the board
back without reordering.

The drop handler built the current on-screen order from
`el.classList[0]` for each `.js-board`. But the board list item is
`li.js-board(class="{{_id}} …")`, and Jade emits the literal `js-board`
class FIRST, so classList[0] is the string "js-board" for every board —
never the board _id. The ordered ids were therefore
['js-board','js-board',…]; computeReorderedSortIndex could not find the
dragged/target ids in that array, returned null, and nothing was written
to profile.boardSortIndex. The preview still worked because it is driven
by the dragover CSS class, independent of the id.

Read each board's _id from its Blaze data context (the same source
dragstart already uses via `this._id`) instead of the literal class, so
the real display order reaches the (already correct, unit-tested) reorder
helper and the drop persists. Add a regression guard in
tests/boardSortReorder.test.cjs asserting the wrong-class extraction
("js-board" repeated) yields no mapping while real ids reorder.
2026-07-08 23:57:39 +03:00
Lauri Ojansivu 372a58c112 Updated ChangeLog. 2026-07-08 23:49:32 +03:00
Lauri Ojansivu 527962966b Add Upcoming WeKan release CHANGELOG section for #6443 fix
Link the fix commit under a new "Upcoming WeKan release" heading, in the
same style as previous release entries.
2026-07-08 23:44:10 +03:00
Lauri Ojansivu a37e7d1cc7 Fix #6443: cards on a deleted swimlane are invisible in swimlane view
On old boards a swimlane can be deleted while its cards keep the now
dangling swimlaneId (an "orphaned" card). Cards with no swimlane at all
(null / '' / missing) already surface in every swimlane, but an orphaned
card matched no existing swimlane and so appeared in NO swimlane in
swimlane view, while still showing in list view (which applies no
swimlane scope) — the reported "no swimlane" symptom where some boards
show no cards in swimlane mode but work in list mode.

Mirror the existing orphaned-LIST fallback (Swimlanes.orphanedSwimlaneLists,
which surfaces orphaned lists in the first swimlane) for cards: when a
list's cards are fetched for the board's FIRST swimlane, build the
swimlane-membership clause as a single { swimlaneId: { $nin:
<otherSwimlaneIds> } } (everything not owned by another existing
swimlane: own id, null/'', missing, or orphaned). This keeps it a single
field clause with no second $or, so the #6441 board-wide label filter
still holds. Orphaned cards therefore appear once, in the first swimlane,
without a database migration.

Threaded through the pure selector helpers (swimlaneMembershipSelector /
listCardsSelector / filteredListCardsSelector) and the in-memory sibling
filterCardsByListAndSwimlane, a new List.orphanedCardsSwimlaneIds helper,
and the cards()/cardsUnfiltered()/allCards() model methods plus the
listBody cardsWithLimit render helper. Covered by new cases in
tests/swimlaneFilter.test.cjs (18 assertions pass; #6441 guards intact).
2026-07-08 23:43:26 +03:00
Lauri Ojansivu 33ad40d012 Updated translations. 2026-07-08 23:12:53 +03:00
Lauri Ojansivu 44b5e12de9 Update README to reflect Meteor version change 2026-07-06 19:07:03 +03:00
github-actions[bot] 1207b573b5 Bump versions for v9.80 2026-07-06 15:40:14 +00:00
Lauri Ojansivu a26295a2fb Updated ChangeLog. 2026-07-06 18:35:50 +03:00
Lauri Ojansivu b2da9ac8d4 Admin Panel Domains table: server-side pagination, column sort and search (like Board Table view). Thanks to xet7. 2026-07-06 18:27:38 +03:00
Lauri Ojansivu 53dcf7379d Updated ChangeLog. 2026-07-06 18:13:31 +03:00
Lauri Ojansivu dfa6c78d4f Add regression test for board-invite email language. Refs #5664. 2026-07-06 16:02:56 +03:00
Lauri Ojansivu 795850ed05 Updated ChangeLog. 2026-07-06 15:25:54 +03:00
Lauri Ojansivu 9ef7f4a07a Thanks to 32Dexter and xet7 . Fixes #5666 2026-07-06 15:22:22 +03:00
Lauri Ojansivu cb2394a95d Updated ChangeLog. 2026-07-06 15:12:21 +03:00
Lauri Ojansivu ac368de06a Thanks to MarcusDger and xet7 . Fixes #5667 2026-07-06 15:12:21 +03:00
github-actions[bot] b26494766f Bump versions for v9.79 2026-07-06 11:46:51 +00:00
Lauri Ojansivu 68ab63c7fe Updated ChangeLog. 2026-07-06 14:43:27 +03:00
Lauri Ojansivu e3e71b254a Updated ChangeLog.
Link #6439/#6440/#6441 and the i18n test fix to their commits; wire the new unit tests into test:unit:node.

Thanks to jullbo and xet7.
2026-07-06 14:35:35 +03:00
Lauri Ojansivu fc4eadedc9 Fix flaky server-side Mocha i18n test (zh-CN "is not a spy")
The .loadLanguage suite intermittently reported "1 failing" (the failure bouncing between the zh-CN and fr cases). Two causes: stubbing the shared TAPi18n.i18n let state leak between tests, and asserting via sinon-chai routed the matcher through chai-as-promised so it could evaluate after afterEach's sinon.restore(). Give each test a fresh i18next instance via TAPi18n.init() (mirrors the reliable .setLanguage suite) and assert with synchronous sinon.assert.* instead of sinon-chai.

Thanks to xet7.
2026-07-06 14:35:34 +03:00
Lauri Ojansivu 9dca403782 Fix #6441: label filter now applies board-wide across all swimlanes
Thanks to jullbo and xet7.
2026-07-06 13:49:44 +03:00
Lauri Ojansivu dd90995db7 Fix #6440: '+' add-item button on minicard checklist now adds the item
Thanks to jullbo and xet7.
2026-07-06 13:49:44 +03:00
Lauri Ojansivu f8e31745d8 Fix #6439: Custom (drag order) sort on All Boards page now reorders via drag-and-drop
Thanks to jullbo and xet7.
2026-07-06 13:49:44 +03:00
280 changed files with 9584 additions and 659 deletions

No files matched your search

+436 -2
View File
@@ -34,10 +34,444 @@ them up next.
[#4560](https://github.com/wekan/wekan/issues/4560) (LDAP→OIDC), [#3707](https://github.com/wekan/wekan/issues/3707)
& [#3700](https://github.com/wekan/wekan/issues/3700) (LDAP), [#3575](https://github.com/wekan/wekan/issues/3575)
(WebHooks), [#1192](https://github.com/wekan/wekan/issues/1192) (Sandstorm).
- **LDAP security/config that needs a real LDAP directory to verify safely (an unverified auth change could lock users out):**
[#4419](https://github.com/wekan/wekan/issues/4419) (after password→LDAP migration the old local password still
works — the safe fix is a `validateLoginAttempt` hook that rejects password-service logins for `authenticationMethod:'ldap'`
users, or `$unset services.password` on migration; both must be tested against a directory before shipping),
[#4158](https://github.com/wekan/wekan/issues/4158) (LDAP_ENCRYPTION naming/docs: accept `starttls`/`true`, deprecate
`tls`/`ssl`, validate unknown values).
- **Need the running app to reproduce/verify (runtime UI or publication/mergebox state), not unit-testable here:**
[#4959](https://github.com/wekan/wekan/issues/4959) & [#4825](https://github.com/wekan/wekan/issues/4825) (per-list
card counts on the All Boards page — the `boardLists`/`boardMembers` helpers in `client/components/boards/boardsList.js`
were deliberately stubbed to `[]` to stop the #4214 "icons random dance"; re-enabling needs a non-reactive count source
and a lists/cards subscription for the dashboard, verified live so #4214 does not return),
[#4822](https://github.com/wekan/wekan/issues/4822) (maximized card mis-positioned after scrolling in swimlanes view),
[#3826](https://github.com/wekan/wekan/issues/3826) (cannot reorder cards in a list full of subtask cards — drag-drop,
data-loss risk), [#5282](https://github.com/wekan/wekan/issues/5282) & [#3252](https://github.com/wekan/wekan/issues/3252)
("Removed nonexistent document" on attachment / comment / checklist delete — a publication/mergebox double-remove, same
class as the fixed #5685, not the delete itself),
[#4897](https://github.com/wekan/wekan/issues/4897) (OAuth2 users intermittently show stale/missing data — caching/
publication timing), [#3276](https://github.com/wekan/wekan/issues/3276) (excessive-time card colour does not refresh to
red until focus leaves the card — reactive re-render), [#3189](https://github.com/wekan/wekan/issues/3189) (Worker-role
user cannot re-assign a card to themselves after a prior assignee was removed — role/deny permission),
[#3576](https://github.com/wekan/wekan/issues/3576) (mobile back button after search returns to settings, not the board),
[#3453](https://github.com/wekan/wekan/issues/3453) (cross-board subtask full-path label vanishes after refresh — router),
[#3378](https://github.com/wekan/wekan/issues/3378) (SyncedCron "duplicate key" in cronHistory for notification_cleanup —
scheduler/dev-reload timing), [#3199](https://github.com/wekan/wekan/issues/3199) (Archive Restore/Delete links need
visual separation from neighbouring cards — CSS refinement),
[#3144](https://github.com/wekan/wekan/issues/3144) (archived-card activities render "undefined" in board settings —
the card lookup returns nothing once the card is archived/unpublished; needs the activity to carry a stored card title
or the feed to fall back to "{title} [archived]", verified live),
[#3114](https://github.com/wekan/wekan/issues/3114) (mobile card view stays open but blank after another client
deletes/moves the card — reactive close-on-remove), [#3037](https://github.com/wekan/wekan/issues/3037) (after moving a
card between boards via the REST API, opening it bounces back to the old board — the raw boardId/listId update does not
go through the full Card.move() re-home; the dedicated REST move/sort/date/archive path was fixed in #5398/#5399/#5537/
#5546, so use that rather than a raw field update), [#3070](https://github.com/wekan/wekan/issues/3070) (using a
template from Add Board / the top bar — issue body would not load; needs the app to reproduce).
- **Already correct in the current code (could not reproduce; endpoint/logic verified by reading):**
[#4774](https://github.com/wekan/wekan/issues/4774) (`POST /users/register` is a native handler that returns 403 only
when registration is disabled via `forbidClientAccountCreation`; it works by default),
[#4055](https://github.com/wekan/wekan/issues/4055) (ISO week number — the native DST-safe `getISOWeek()` is correct;
a regression test was added this release).
- **Incomplete report (no reproduction details provided by the reporter):**
[#4593](https://github.com/wekan/wekan/issues/4593) (new team member permissions — issue body empty).
- **Feature requests / behaviour-by-design rather than bugs:**
[#5547](https://github.com/wekan/wekan/issues/5547), [#3843](https://github.com/wekan/wekan/issues/3843),
[#3823](https://github.com/wekan/wekan/issues/3823), [#3138](https://github.com/wekan/wekan/issues/3138),
[#5547](https://github.com/wekan/wekan/issues/5547), [#3843](https://github.com/wekan/wekan/issues/3843)
(attachments added in comments not shown in the card attachment list),
[#3828](https://github.com/wekan/wekan/issues/3828) (board members seeing all cards on a board is by design — WeKan has
no per-card visibility model), [#3823](https://github.com/wekan/wekan/issues/3823),
[#3748](https://github.com/wekan/wekan/issues/3748) (linked cards mirror the original rather than owning their own
labels/custom fields), [#4023](https://github.com/wekan/wekan/issues/4023) (Japanese font alignment → per-board font
request), [#4043](https://github.com/wekan/wekan/issues/4043) (invitation email occasionally sent without a valid
code), [#3138](https://github.com/wekan/wekan/issues/3138),
[#2204](https://github.com/wekan/wekan/issues/2204) (restrict permanent delete to the Admin role).
- **Needs a maintainer decision on the intended contract (partly already works):**
[#4912](https://github.com/wekan/wekan/issues/4912) (a global `act-editCard` webhook — card title/description edits
ALREADY reach the global webhook via `Activities.after.insert` as `act-a-changedTitle` / `act-a-changedDescription`
from #3619/#5482; a single consolidated `act-editCard` action needs a decision on which fields count and whether it
supplements or replaces the existing per-field events, to avoid duplicate webhook deliveries),
[#3113](https://github.com/wekan/wekan/issues/3113) (webhook `user` field shows the full name, not the username — the
same `params.user` feeds both the e-mail notification text, where the full name is intended, and the webhook payload,
where a username is expected; the safe change is to ADD a `username` field to the webhook rather than repurpose `user`).
# v9.83 2026-07-09 WeKan ® release
This release fixes the following bugs:
- **[Fix #3624 swimlane REST regression: await the async board.swimlanes()](https://github.com/wekan/wekan/commit/6a6db32884f68dadd5911ec3487225c908f40176)**:
The swimlanes CRUD e2e test (23-rest-api-more.e2e.js:209) regressed on all
browsers. Root cause: on the server ReactiveCache.getSwimlanes is async, so
board.swimlanes() returns a Promise in the REST handler. The #3624 change read
board.swimlanes().map(s => s.sort); .map on a Promise throws, the insert never
ran, the error was swallowed by the handler's catch (returned as 200 with no
_id), and the test read .title off a null swimlane.
The earlier "move the require to a top-level import" commit was not the real
cause (the same module.exports import pattern works server-side, e.g.
ruleDeletePermission in rulesButton.js). The actual fix is to await
board.swimlanes() before mapping. This also means API-created swimlanes now get
a real max(existing sort)+1 sort — previously the un-awaited `.length` yielded
undefined, so they were stored with no sort at all, which is the #3624 symptom.
Verified: the swimlane test passed in every kept local run through
2026-07-09_02-38-07 and failed starting 09-52-25 (right after the #3624 change),
confirming the regression window; the tests/swimlaneSort.test.cjs unit test
still passes.
Thanks to above GitHub users for their contributions and translators for their translations.
# v9.82 2026-07-09 WeKan ® release
This release fixes the following bugs:
- **[Fix #5536: automated rule can now move/link a card to a different board](https://github.com/wekan/wekan/commit/18153cbc556823318a31766935dd3d718a88eaee)**:
The rules "move card to top/bottom of a list on another board" and "link
card to another board" actions failed for boards the rule creator did not
own. The action showed BLANK after creating the rule (the wizard's optimistic
client inserts landed in minimongo limbo / were rejected by allow-deny for
non-owner members) — these now create the rule through the server
`rules.createRule` method, keeping the action's destination boardId. And
execution crashed with an "Internal Server Error" because the destination
swimlane fallback dereferenced `._id` on a possibly-undefined swimlane titled
exactly `Default` (renamed/translated/deleted on the destination board);
resolution now uses the board's real default swimlane via a Meteor-free
resolver `models/lib/ruleActionResolve.js`, unit tested in
`tests/ruleActionResolve.test.cjs`. Thanks to DarthKillian and xet7.
- **[Fix #4978: board background updates when switching boards via the favorites bar](https://github.com/wekan/wekan/commit/af6ed501c6f341c3c1fbceade704ef0ae69a5669)**:
Switching directly between two boards via the favorites bar reused the same
boardBody template instance, so the one-shot `setBackgroundImage()` in
onRendered never re-ran and the previous board's background stuck. It is now
applied inside a reactive autorun and clears any stale inline background when
the new board has no image. The decision is a Meteor-free helper
`models/lib/boardBackground.js`, unit tested in `tests/boardBackground.test.cjs`.
Thanks to dasarne and xet7.
- **[Fix #4881: Due this week / next week filter respects the start day of week](https://github.com/wekan/wekan/commit/b4a83462c39fb4be2e1c33aa7c90e690abffc79e)**:
The "Due this week" filter selected next week's cards and ignored the
configured start weekday, because it derived its window from
`startOf(now(), 'week')` — which the native dateUtils never implemented, so
it returned the date unchanged. A new Meteor-free helper
`models/lib/weekStart.js` computes the correct week window for any start day
of week; the this/next-week buttons now toggle per week too. Unit tested in
`tests/weekStart.test.cjs`. Thanks to mimZD and xet7.
- **[Fix #4946: calendar week numbers respect the defined start day of week](https://github.com/wekan/wekan/commit/9f9430595507d5e305f3919bd0d3f5298239e971)**:
In the Calendar view the week-number column was numbered from Sunday
regardless of the start-day-of-week setting. The calendar now computes the
number with `weekNumberByFirstDay()` (in `models/lib/weekStart.js`) from the
same firstDay used to lay out the grid, unit tested in
`tests/weekStart.test.cjs`. Thanks to helioguardabaxo and xet7.
- **[Fix #4653: LDAP username with a hyphen no longer becomes a dot](https://github.com/wekan/wekan/commit/a780c8b2a2c558a2b6e79f64b075007836af24d1)**:
With `LDAP_UTF8_NAMES_SLUGIFY` enabled, `limax(text, { separator: '.' })`
turned every non-alphanumeric run — hyphens included — into `.`, so an LDAP
username like `p.parta-partb` became `p.parta.partb` and the user could not
log in. The username is now slugified per hyphen-separated segment and
rejoined with `-`, preserving hyphens while still transliterating UTF-8. Pure
helper `packages/wekan-ldap/server/usernameSlug.js`, unit tested in
`tests/ldapUsernameSlug.test.cjs`. Thanks to RowhamD and xet7.
- **[Fix #4236: Enter adds a new line in the card title, consistent with the description](https://github.com/wekan/wekan/commit/aa5241a1ef3a8611701d4fb28e5d5b9e67f74900)**:
The card title textarea submitted on plain Enter (only Shift+Enter made a new
line), unlike the description field which inserts a new line on Enter and
saves on Ctrl/Cmd+Enter. The title now uses the same shared, Meteor-free rule
`isSubmitKey()` (`models/lib/editorSubmitKey.js`): submit only on
Ctrl/Cmd+Enter, newline otherwise. Unit tested in
`tests/editorSubmitKey.test.cjs`. Thanks to listenerri and xet7.
- **[Fix #4055: ISO week-number regression test (already correct in current code)](https://github.com/wekan/wekan/commit/4e9614894a3b8eb23286f834c6bc4183f861d7eb)**:
#4055 reported the week number was one/two weeks too high for 2021-10-25..31
(ISO week 43). That was the old moment-based math; the current native,
DST-safe `getISOWeek()` computes it correctly. Added
`tests/isoWeek.test.cjs` pinning the reported dates so it cannot regress.
Thanks to marcungeschikts and xet7.
- **[Fix #4394: Register / Forgot Password links stay hidden after a failed login](https://github.com/wekan/wekan/commit/9e754e69b60509e3cb7abc9bef3bc61e27d3fa84)**:
Security. With registration / forgot-password disabled in the Admin Panel, the
links were hidden by a one-shot `.hide()` that a useraccounts form re-render
(e.g. an LDAP failed login) dropped, so the links reappeared. The disable
state is now a class on the stable `<body>` ancestor with matching CSS, so the
links are re-hidden on every re-render. Thanks to Alsterdetektive1 and xet7.
- **[Fix #4494: creating a board from a template no longer breaks subtasks](https://github.com/wekan/wekan/commit/032f06feb825ba62aebddfdc24f494812195542b)**:
A board created from a template inherited the template's
subtasksDefaultBoardId / dateSettingsDefaultBoardId; when those pointed at the
template board itself, subtasks created on the new board were dropped onto the
TEMPLATE board and linked back across boards. Board.copy() now repoints such
self-referential defaults to the copy and clears the paired list id so it
self-heals on the new board. Pure helper `models/lib/boardCopyDefaults.js`,
unit tested in `tests/boardCopyDefaults.test.cjs`. Thanks to Xilef11 and xet7.
- **[Fix #4249: filter by card title now works for renamed linked cards](https://github.com/wekan/wekan/commit/e089e176345452956889f709f0eb05b1687bec2c)**:
Renaming a linked card wrote the new title only to the linked target, leaving
the linking card's own title field stale; filter-by-title queries the own
field, so linked cards dropped out of title filters after a rename.
Card.setTitle() now also writes the linking card's own title. Pure helper
`models/lib/linkedCardTitle.js`, unit tested in
`tests/linkedCardTitle.test.cjs`. Thanks to Ben0it-T and xet7.
- **[Fix #3606: activity feed no longer shows "edited/deleted comment undefined"](https://github.com/wekan/wekan/commit/4c721b997514d5e6659cf1725c719238d6db3e58)**:
The feed passed the comment id (absent on old activities, and gone for a
deleted comment) into the activity string. Edit/delete activities now store
the comment text and render it via `Activities.commentDisplayText()`, which
falls back to the live comment text and then to an empty string — never
"undefined". Pure helper `models/lib/commentActivity.js`, unit tested in
`tests/commentActivity.test.cjs`. Thanks to janchuelo and xet7.
- **[Fix #3624: new_swimlane REST API appends the swimlane last and accepts a sort](https://github.com/wekan/wekan/commit/04021f8c1df4b8e8f285a4cfffc03404ada4188e)**:
`POST /api/boards/:boardId/swimlanes` set the sort to the swimlane count, so a
new swimlane appeared FIRST when existing sort values were non-contiguous. It
now appends at max(existing sort)+1 and honors an optional explicit `sort` in
the body. Pure helper `models/lib/swimlaneSort.js`, unit tested in
`tests/swimlaneSort.test.cjs`. Thanks to tamasberesoebb and xet7.
- **[Fix #3185: copying a card (or template) now copies its subtasks' checklists](https://github.com/wekan/wekan/commit/fae7bcaa416d766c32d46b29b91e3fc6b7d022ce)**:
Copying a card inserted each subtask as a bare card document, so the subtasks'
checklists (and items) were dropped and the copied subtasks came out empty.
Card.copy() now copies each subtask's checklists onto the new subtask. Pure
helper `models/lib/subtaskCopy.js`, unit tested in `tests/subtaskCopy.test.cjs`.
Thanks to ramses345 and xet7.
- **[Fix #5439: list scrollbar is always visible on desktop and mobile browsers](https://github.com/wekan/wekan/commit/82e0afa38f50223959cc3cc0091c52da7af93840)**:
List bodies used `overflow-y: auto`, so overlay scrollbars (macOS/iOS/Android/
Firefox) auto-hid. The list body now keeps a scrollbar visible across all
engines — `overflow-y: scroll`, `::-webkit-scrollbar` (Chrome/Safari/Edge/
mobile WebKit), `scrollbar-width`/`scrollbar-color` (Firefox/Gecko) and
`scrollbar-gutter: stable`. Cross-browser rules in `models/lib/scrollbarCss.js`,
applied in `client/components/lists/list.css`, unit tested (builder contract +
applied CSS, positive + negative) in `tests/scrollbarCss.test.cjs`. Thanks to xet7.
- **[Fix #6444: RTL — typing a card title no longer garbles other lists' minicard titles](https://github.com/wekan/wekan/commit/3aaf8f9b6180661abb0a86becf15710fc6937ef8)**:
In an RTL language (e.g. Arabic) the board root is `dir="rtl"`, and both the
minicard title (a `dir="auto"` `.viewer`) and the add-card composer textarea
were `dir="auto"` with no bidi isolation, so they shared the surrounding
bidirectional context. Typing a strong RTL character into one list's composer
re-resolved that shared context and visibly reflowed the displayed minicard
titles of the OTHER lists (no data change, reverted on refresh). Each title and
the composer now use `unicode-bidi: isolate`. Locked in (positive + negative)
by `tests/minicardBidiIsolation.test.cjs`; browser RTL behaviour is covered by
`tests/playwright/specs/18-rtl-layout.e2e.js`. Thanks to xet7.
- **[Fix the Playwright CI test failures introduced by the #3624 and #4236 fixes above](https://github.com/wekan/wekan/commit/6a6db32884f68dadd5911ec3487225c908f40176)**:
Two browser tests failed on Chromium, Firefox and WebKit after this release's
changes. (1) `23-rest-api-more.e2e.js:209` (swimlanes CRUD): on the server
`ReactiveCache.getSwimlanes` is async, so `board.swimlanes()` returns a Promise
in the REST handler. The #3624 change read `board.swimlanes().map(s => s.sort)`;
`.map` on a Promise throws, so `POST /api/boards/:boardId/swimlanes` never ran
the insert, the error was swallowed by the handler's `try/catch` (returned as
200 with no `_id`), and the test read `.title` off a `null` swimlane. The old
`board.swimlanes().length` had tolerated the un-awaited Promise by silently
yielding `undefined` (so API-created swimlanes were stored with no sort at all —
the very #3624 symptom). Fixed by `await`ing `board.swimlanes()` before mapping,
which also gives API-created swimlanes a real `max(sort)+1` value.
(2) `02-cards-open-view.e2e.js:93` (editing the card title): #4236 deliberately
made plain Enter insert a newline in the card title (Ctrl/Cmd+Enter saves), but
the `CardPage` page object still saved with plain Enter, so the title never
persisted and the read timed out — updated to save with `Control+Enter`
([`984ec16`](https://github.com/wekan/wekan/commit/984ec160daec54b0e6b16cd15d89884f1c4fadf1)).
The server-side Mocha, import-regression and Node E2E jobs were already green;
this makes the Playwright jobs green too. Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v9.81 2026-07-09 WeKan ® release
This release adds the following new features:
- **[Feature #5394: the Link-card popup's Cards dropdown is now sorted alphabetically](https://github.com/wekan/wekan/commit/b07c4d0a7bed0f03ba2d7d1ad1f030e7edf3dfff)**:
In the "Link to this card" popup, the Cards pull-down list is now sorted
alphabetically by card title (case-insensitive, locale/numeric aware)
instead of board sort order, so a card can be found on boards with many
cards. Thanks to xet7.
- **[Feature #5396: edit Lists (title, color) via the REST API + api.py commands](https://github.com/wekan/wekan/commit/7ce71dbb2e1eae5159503eefac7e6f349dfb59c8)**:
Lists can now be edited through the REST API like cards can. The endpoint
`PUT /api/boards/:boardId/lists/:listId` already accepted `title`, `color`,
`starred` and `wipLimit`, but the color was stored unvalidated; it now
validates the color with `normalizeListColor` (a named palette color or a
custom `#rrggbb` hex) and rejects an unknown color with a clear 400 instead
of silently storing None. The pure field/validation logic lives in a
Meteor-free helper `models/lib/listApiUpdate.js` and is unit tested in
`tests/listApiUpdate.test.cjs`. The `api.py` reference CLI gains two new
commands mirroring `editcard`/`editcardcolor`: `editlist BOARDID LISTID
NEWLISTTITLE` and `editlistcolor BOARDID LISTID COLOR`. Thanks to C0rn3j and xet7.
- **[Feature #5514: custom color-wheel (RGB/hex) picker with automatic readable text contrast](https://github.com/wekan/wekan/commit/30f36a7f319675bd3aac7a4ba0700427000726b9)**:
The color pickers that previously offered only a fixed set of named colors now also include a native
color wheel (`<input type="color">`), so any `#rrggbb` color can be chosen. The wheel was added
alongside the existing swatches for card labels ("categories"), swimlanes ("tabs"), lists and cards.
The schema color fields accept a custom hex in addition to the named palette, and existing named-color
data keeps working; a stored hex is rendered with an inline `background-color` instead of the named
CSS class. A new pure, Meteor-free helper `models/lib/contrastColor.js` computes a readable text color
from sRGB relative luminance (white text on dark backgrounds, black on light), maps the named palette
to hex, and validates/normalizes hex; it is applied as an inline text color wherever a chosen color is
a background behind text (label chips, swimlane / list headers, minicard, card details header), so text
stays readable on any color. Covered by `tests/contrastColor.test.cjs` (20 assertions pass).
Thanks to Ruyeex and xet7.
- **[Feature #5621: Rules can set a date field to a custom time (value + minute/hour/day/week/month later)](https://github.com/wekan/wekan/commit/53328f40c6e092988175ce820c14658c855390de)**:
The Rules "Set date relative to now" action previously only offset a date field (Start / Due / End /
Received) by a whole number of DAYS. It now has a unit selector, so a rule can set a date field to
now + `<value>` `<unit> later`, where the unit is minute(s) / hour(s) / day(s) / week(s) / month(s);
negative values move the date earlier. Months use a real calendar-month add (e.g. keeping the same
day-of-month) rather than a fixed 30-day approximation. Existing rules created before this change
have no stored unit and keep working exactly as before (no unit ⇒ days), so the change is fully
backward compatible. The offset math lives in a new pure, Meteor-free helper
`models/lib/relativeDateOffset.js` used by `server/rulesHelper.js` and covered by
`tests/relativeDateOffset.test.cjs` (15 assertions pass). Note that the related "overdue" Rules
trigger and the "set date field to now" action from the same feature request already existed in an
earlier release; this change adds only the missing custom-time unit selector. Thanks to xet7.
and fixes the following bugs:
- **[Fix #5351: users are auto-added to organizations matching their email domain on sign-up](https://github.com/wekan/wekan/commit/d41e17d6a088edf6abbb1f9517d2ecb58d618f03)**: the Organization setting "Automatically add users with the domain name" (`org.orgAutoAddUsersWithDomainName`) could be configured, but nothing at sign-up ever read it, so a new user whose email domain matched an organization was never added to it; the `Accounts.onCreateUser` hook now, on every non-admin sign-up path (password registration, LDAP, invitation code, new OIDC user), adds the user to each organization whose configured domain exactly matches the domain part of their email (case-insensitive, exact — a subdomain does not match and an empty org domain matches nobody), using the same `{ orgId, orgDisplayName }` membership shape used everywhere else and never duplicating an existing membership, with the matching decision extracted into a Meteor-free, unit-tested `orgsToAutoAddForEmail` helper.
Thanks to xet7.
- **[Fix #5369: the Activities show/hide control is now a clear eye / eye-slash icon toggle](https://github.com/wekan/wekan/commit/1ce2d8cc8871e5da6f0ce5dde04520885649c0ba)**: the Activities panel's show/hide control was a generic, unlabeled material toggle switch whose ON/OFF meaning was counterintuitive; it is replaced on the card details Activities panel with an eye / eye-slash icon toggle (open eye = activities shown, crossed eye = activities hidden) that mirrors the login/register password-visibility toggle, so the icon reflects the current visibility, clicking flips it, and the tooltip states the action (Show activities / Hide activities). For consistency the board sidebar Activities toggle, which drives the same showActivities state, was switched from the check / empty-square icon to the same eye / eye-slash toggle. The underlying show/hide setting and its persistence are unchanged.
Thanks to xet7.
- **[Fix #5442: outgoing webhooks now include the label name on add/remove label](https://github.com/wekan/wekan/commit/aad00cdba2bb896068f4a896cf67df2a7bd79a73)**: the addedLabel/removedLabel outgoing webhook (and notification) text showed a bare, generic "label" with no name, because labels are embedded in the board document but the Activities `label()` helper looked the label id up in the Cards collection and always returned undefined, so the `__label__` token was never filled; the hook now resolves the label from the already-loaded board via `getLabelById` and a pure, unit-tested `labelDisplayName` helper (name, then color for a nameless label as shown in the UI, then the id), so the webhook always carries the label's display name.
Thanks to xet7.
- **[Fix #5482: adding/editing a card description now triggers outgoing webhooks](https://github.com/wekan/wekan/commit/da0d338e336ecfd3c120753aaea064e9487bf3cd)**: outgoing webhooks fire only when an operation logs an activity (the Activities.after.insert hook posts to the board's webhooks), but changing a card's description created no activity — unlike title/date changes — so no webhook was sent; the Cards before.update hook now logs an `a-changedDescription` activity on first-time set and later edits (but not on no-op / empty-to-empty saves), so the existing webhook hook fires, with a Meteor-free unit-tested `descriptionChanged` helper.
Thanks to xet7.
- **[Fix: the Rules Workflow view is now fully translatable via i18n](https://github.com/wekan/wekan/commit/8c499823cbc8c5785ec604015d55e28daa11336e)**: the Rules Workflow view rendered its trigger/action palette chips ("Card is created", "Move card to top", "Set received date to now", etc.) as hardcoded English regardless of the UI language, while the rest of the page was translated; each palette entry now carries an i18n key translated at render time via TAPi18n.__ (reusing existing rule keys where they fit, plus new r-w-* keys for workflow-only labels), and the slot clear tooltip now uses the existing r-remove key, so the whole view follows the selected language.
Thanks to xet7.
- **[Fix: deleting a board rule no longer fails with "Access denied [403]"](https://github.com/wekan/wekan/commit/68dd14140f620574a95db42dc1078a7b4bd97916)**: deleting a rule ran three separate client-side Collection.remove() calls (Rules + Triggers + Actions), each gated by a per-collection allow() rule that resolved the board from that document's own boardId; when a trigger/action document had no resolvable boardId (legacy docs, or docs not published to the client) the board came back null, `allowIsBoardAdmin` returned false, and Meteor rejected the mutation with 403 "Access denied" — so the delete failed even for a legitimate board admin. Rule deletion now goes through a new server method `rules.deleteRule` that 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 a Meteor-free, unit-tested helper and no permission is loosened.
Thanks to xet7.
- **[Fix #5510: adding a board label via the REST API no longer errors/hangs](https://github.com/wekan/wekan/commit/0e9aed5a4b359188a9390f1132443614b3b0e133)**: PUT /api/boards/:boardId/labels only sent a response when the body had a `label` key, so a body without one hung until the client timed out, and a bare-string `label` pushed a schema-invalid label and returned 200; the handler now always returns JSON (2xx on success, 4xx on bad input, real error status otherwise) via a pure, unit-tested input helper.
Thanks to xet7.
- **[Fix #5604: CSV export no longer crashes on boards with dangling references](https://github.com/wekan/wekan/commit/d01526bbff892a946a58aae1b516bd0b82d23113)**: exporting a large/old board to CSV failed with "Couldn't download - Network issue" because Exporter.buildCsv read `.title`/`.username`/`.name` directly on the result of looking up a card's deleted list/swimlane/owner/member/assignee/label/customField by id, throwing "Cannot read property 'title' of undefined"; the per-card row builder is now a null-safe helper that emits a blank cell for missing references while keeping identical output for well-formed cards.
Thanks to xet7.
- **[Fix #5656: the Calendar view now honors the active board filters](https://github.com/wekan/wekan/commit/b0da9097c18dea12ccce8dec6de8a5cf2519551a)**: the Calendar view queried cards by board and date only and ignored the active Filter sidebar (member / assignee / due-date / label / custom-field), so it showed every card in the interval unlike the Board / Lists / Swimlanes views; it now ANDs the Filter selector into its query and refetches when the filter changes.
Thanks to kerier and xet7.
- **[Fix #6442: All Boards "Custom (drag order)" — drop now persists the reorder](https://github.com/wekan/wekan/commit/457713968cf3c365899271606398b7796a7b07f4)**:
Follow-up to #6439, which restored the drag preview but left the drop a no-op: dragging a board on
the All Boards page in Custom (drag order) mode showed the dashed-border preview, but releasing it
snapped the board back without reordering. The drop handler built the current on-screen order from
`el.classList[0]` of each `.js-board`, but the item is `li.js-board(class="{{_id}} …")` and Jade
emits the literal `js-board` class FIRST, so `classList[0]` was the string `"js-board"` for every
board — never the board `_id`. The ordered ids were therefore `['js-board','js-board',…]`, the
(correct, unit-tested) `computeReorderedSortIndex` helper could not find the dragged/target ids
among them, returned `null`, and nothing was written to `profile.boardSortIndex`; the preview still
worked because it is driven by the `dragover` CSS class, independent of the id. The fix reads each
board's `_id` from its Blaze data context (the same source `dragstart` uses via `this._id`) instead
of the literal class, so the real display order reaches the reorder helper and the drop persists.
Guarded by a new case in `tests/boardSortReorder.test.cjs` (the wrong-class extraction yields no
mapping; real ids reorder).
Thanks to jullbo and xet7.
- **[Fix #6443: cards on a deleted swimlane are invisible in swimlane view](https://github.com/wekan/wekan/commit/a37e7d1cc7e1a4541c498c974aa97b2e36136065)**:
On some old boards a swimlane was deleted while its cards kept the now-dangling `swimlaneId` (an
"orphaned" card), so those cards showed no content in swimlane mode even though they worked in list
mode. Cards with no swimlane at all (`null` / `''` / missing) already appear in every swimlane, but
an orphaned card matched no existing swimlane and so was visible in NO swimlane (while list view,
which applies no swimlane scope, still showed it) — exactly the reported symptom. The fix mirrors
the existing orphaned-**list** fallback (`Swimlanes.orphanedSwimlaneLists`, which surfaces orphaned
lists in the first swimlane) for **cards**: when a list's cards are fetched for the board's FIRST
swimlane, the swimlane-membership clause becomes a single `{ swimlaneId: { $nin: <otherSwimlaneIds> } }`
(everything not owned by another existing swimlane: own id, `null`/`''`, missing, or orphaned). It
stays a single field clause with no second `$or`, so the #6441 board-wide label filter still holds,
and orphaned cards appear once — in the first swimlane — without a database migration. Threaded
through the pure `models/lib/swimlaneFilter.js` helpers, the in-memory `filterCardsByListAndSwimlane`,
a new `List.orphanedCardsSwimlaneIds` helper and the `cards()`/`cardsUnfiltered()`/`allCards()` model
methods plus the `listBody` `cardsWithLimit` render helper. Covered by new cases in
`tests/swimlaneFilter.test.cjs` (18 assertions pass; the #6441 regression guards stay intact).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v9.80 2026-07-06 WeKan ® release
This release adds the following new features:
- **[Admin Panel Domains table: pagination, column sort and search (like the Board Table view)](https://github.com/wekan/wekan/issues/5850)**:
The Admin Panel > People > Domains table loaded every domain (aggregated from all users) into the
browser at once, with a fixed order and no search. It now behaves like the Board Table view: the
server aggregates the domains and returns only one small page, so the whole list is never sent to
the browser. You can order by the Domain or Users column (click the header to toggle ascending /
descending, with a ▲/▼ indicator) and filter with a search box; prev/next controls page through the
results. The search + sort + slice runs in the new pure, unit-tested `models/lib/domainTablePage.js`
behind a new `getDomainsWithUserCountsPage` admin method (`server/models/users.js`), and the
`domainGeneral` template (`client/components/settings/peopleBody.{jade,js,css}`) is now
self-contained and fetches only the current page. Covered by `tests/domainTablePage.test.cjs`.
Thanks to xet7.
and adds the following tests:
- **[Verified and added a regression test for the board-invitation email language](https://github.com/wekan/wekan/commit/dfa6c78d4f032a698f6feaad189c86da903d27fb)**:
Confirmed that a board-invitation email is localised in the existing recipient's own profile
language, or — when the invitee is a new account created by the invite — in the inviter's profile
language, defaulting to `en` (`en.i18n.json`) when none is set. The behaviour was already correct;
the language choice is now extracted into the pure, unit-tested `models/lib/inviteEmailLanguage.js`
used by `inviteUserToBoard`, and locked in by `tests/inviteEmailLanguage.test.cjs`.
Thanks to xet7.
and fixes the following bugs:
- **[Linked-card minicard now shows the cover image of the real card](https://github.com/wekan/wekan/commit/9ef7f4a07a6b40a2582af24b27fe133119adcd18)**:
A linked card (created by "Link card to this card") on one board did not show the cover image of
the real card it points at on another board, even though the card's other fields did. A linked
card is only a placeholder — its real content lives on the card at `linkedId` — and every other
minicard getter resolves through the real card (`getTitle`/`getReceived`/`getDue`/…), but the
cover helpers read `this.coverId` directly, and a linked card has no `coverId` of its own. The
real card's cover attachment is already published to the linking board (see the "linked cards" /
"attachments for linked cards" children of the `board` publication), so this was purely a
client-side resolution gap. `Card.cover()` and the minicard `cover()` helper now resolve the
cover id through the real card via the pure, unit-tested `models/lib/linkedCardCover.js`; normal
cards are unaffected. Covered by `tests/linkedCardCover.test.cjs`.
Thanks to 32Dexter and xet7.
- **[Fix date-picker calendar stays fully visible when opened low on a scrolled page](https://github.com/wekan/wekan/commit/7a0eb61c0a4d3ace60f95cfbda7c1d70dff665ef)**:
Opening a date field (due/start/end date, or a date custom field) low on the screen showed the
calendar popup extending past the visible area, and — because the pop-over is `position: absolute`
(document coordinates) — scrolling to reach it moved the calendar along with the page, so the full
calendar could never be seen (the workaround was to close it, drag the field to the center and
reopen). `Popup._getOffset` computed the space above/below the opener and the clamped `top` from
the opener's DOCUMENT offset mixed with the VIEWPORT height, ignoring the page scroll, so on a
scrolled page the anchored popup landed outside the visible viewport. The geometry now runs in
viewport coordinates (subtracting the page scroll) and clamps the popup fully within the visible
viewport, then converts back to document coordinates for the absolute style; when the page is not
scrolled the output is unchanged. Extracted the math into the pure, unit-tested
`client/lib/popupOffset.js`, used by `client/lib/popup.js`. Covered by `tests/popupOffset.test.cjs`.
Thanks to MarcusDger and xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v9.79 2026-07-06 WeKan ® release
This release fixes the following bugs:
- **[Fix #6439: Custom (drag order) sort on All Boards page now reorders via drag-and-drop](https://github.com/wekan/wekan/commit/f8e31745d8104c58dc7bbcb4c1e4c615141a8e82)**:
On the All Boards page the jQuery-ui sortable that reordered boards in the "Custom (drag order)"
mode was removed when the page switched to HTML5 drag-and-drop for workspaces, and nothing
replaced it, so dragging a board showed a not-allowed cursor and never updated
`profile.boardSortIndex`. Added HTML5 `dragover`/`drop` reorder handlers on the board tiles in
`client/components/boards/boardsList.js` (active only in the custom sort mode), a
`setBoardSortIndexes` helper in `models/users.js` to persist the new order in one write, a
drop-hint style in `client/components/boards/boardsList.css`, and extracted the reorder
decision/index math into the pure, unit-tested `models/lib/boardSortReorder.js`. Covered by
`tests/boardSortReorder.test.cjs`.
Thanks to jullbo and xet7.
- **[Fix #6440: '+' add-item button on minicard checklist does nothing](https://github.com/wekan/wekan/commit/dd90995db74593228d40bc504405620ec09c175d)**:
On the minicard the checklist add-item `<form>` is rendered inside the `a.minicard-wrapper`
anchor, so the native form `submit` event never reached the Blaze event map — the #5565
minicard-checklist work wired only a `submit .js-add-checklist-item` handler (which never fires
there) and gave the Save button no click handler, so clicking "+" Save did nothing. Added an
explicit `click .js-submit-add-checklist-item-form` handler in
`client/components/cards/minicard.js` (mirroring the working edit-item button) that inserts the
item, with the blank-input guard and title parsing extracted into the pure, Meteor-free
`models/lib/checklistItemTitles.js`. Card-detail checklists are unaffected. Covered by
`tests/checklistItemTitles.test.cjs`.
Thanks to jullbo and xet7.
- **[Fix #6441: label filter now applies board-wide across all swimlanes](https://github.com/wekan/wekan/commit/9dca403782d476eb3c593fe614848ef02bb7f5a3)**:
A label filter hid non-matching cards in one swimlane (e.g. "Focus") but left another swimlane
(e.g. "Background") unfiltered. Each list scopes its cards to the current swimlane while also
showing shared/orphaned cards that have no swimlane; that fallback was written as a bare
top-level `$or`, which competes with the board Filter's own top-level `$or` (label/member
criteria) when the two selectors are combined — dropping the label criterion in every swimlane
except the default one. The swimlane-membership fallback is now a single
`swimlaneId: { $in: [id, null, ''] }` clause (the same form already used in `sidebarFilters.js`,
`cardDetails.js` and `dialogWithBoardSwimlaneList.js`), extracted to the pure, unit-tested
`models/lib/swimlaneFilter.js` and used by `client/components/lists/listBody.js` and
`models/lists.js`, so no second `$or` exists and the filter is always `$and`-combined and applied
board-wide. Covered by `tests/swimlaneFilter.test.cjs`.
Thanks to jullbo and xet7.
- **[Fix flaky server-side Mocha test (i18n zh-CN "is not a spy")](https://github.com/wekan/wekan/commit/fc4eadedc9109602ee029b60c44eeda869aa98c3)**:
The server-side Mocha suite intermittently reported "1 failing" on the #5756
`imports/i18n/i18n.test.js` region-tag test with `TypeError: [Function] is not a spy`. The
assertion re-read `TAPi18n.i18n.addResourceBundle`, and the sinon-chai matcher (routed through
chai-as-promised) could evaluate after this suite's `afterEach` had already run
`sinon.restore()` — at which point the property is the original function, not the stub. The
`.loadLanguage` tests now assert on the captured stub reference (restore unwraps the property but
leaves the spy intact), which is deterministic. Reproduced and verified with a standalone
sinon/chai script.
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v9.78 2026-07-06 WeKan ® release
+1 -1
View File
@@ -7,7 +7,7 @@ LABEL org.opencontainers.image.source="https://github.com/wekan/wekan"
# TARGETARCH and TARGETVARIANT are automatically provided by Docker Buildx
ARG TARGETARCH
ARG TARGETVARIANT
ARG VERSION=9.78
ARG VERSION=9.83
ARG DEBIAN_FRONTEND=noninteractive
ENV BUILD_DEPS="apt-utils gnupg wget bzip2 g++ curl libarchive-tools build-essential git ca-certificates python3 unzip"
+1 -1
View File
@@ -103,7 +103,7 @@ By working directly with WeKan ® you get the benefit of active maintenance and
## Getting Started with Development
The default branch uses Meteor 3.5-rc.2 with Node.js 24.x.
The main branch uses Meteor 3.5 with Node.js 24.x.
See [CHANGELOG.md](https://github.com/wekan/wekan/blob/main/CHANGELOG.md) for the latest runtime updates.
To contribute, [create a fork](https://github.com/wekan/wekan/blob/main/docs/DeveloperDocs/Build-and-Create-Pull-Request.md#2-create-fork-of-httpsgithubcomwekanwekan-at-github-web-page) and run `./rebuild-wekan.sh` (or `./rebuild-wekan.bat` on Windows) as detailed [here](https://github.com/wekan/wekan/blob/main/docs/DeveloperDocs/Build-and-Create-Pull-Request.md#3-select-option-1-to-install-dependencies-and-then-enter). Once you're ready, please test your code and [submit a pull request (PR)](https://github.com/wekan/wekan/blob/main/docs/DeveloperDocs/Build-and-Create-Pull-Request.md#7-test).
+1 -1
View File
@@ -1,5 +1,5 @@
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
appVersion: "v9.78.0"
appVersion: "v9.83.0"
files:
userUploads:
- README.md
+45
View File
@@ -37,6 +37,8 @@ If *nix: chmod +x api.py => ./api.py users
python3 api.py lists BOARDID # Lists of BOARDID
python3 api.py list BOARDID LISTID # Info of LISTID
python3 api.py createlist BOARDID LISTTITLE # Create list
python3 api.py editlist BOARDID LISTID NEWLISTTITLE # Edit list title
python3 api.py editlistcolor BOARDID LISTID COLOR (Color available: `white`, `green`, `yellow`, `orange`, `red`, `purple`, `blue`, `sky`, `lime`, `pink`, `black`, `silver`, `peachpuff`, `crimson`, `plum`, `darkgreen`, `slateblue`, `magenta`, `gold`, `navy`, `gray`, `saddlebrown`, `paleturquoise`, `mistyrose`, `indigo`) # Edit list color
python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION
python3 api.py editcard BOARDID LISTID CARDID NEWCARDTITLE NEWCARDDESCRIPTION
python3 api.py getcard BOARDID LISTID CARDID # Get card info
@@ -432,6 +434,49 @@ if arguments == 5:
if arguments >= 4:
if sys.argv[1] == 'editlist':
# ------- EDIT LIST START -----------
boardid = sys.argv[2]
listid = sys.argv[3]
newlisttitle = sys.argv[4]
edlist = wekanurl + apiboards + boardid + s + l + s + listid
print(edlist)
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
put_data = {'title': '{}'.format(newlisttitle)}
body = requests.put(edlist, data=put_data, headers=headers)
print("=== EDIT LIST ===\n")
body = requests.get(edlist, headers=headers)
data2 = body.text.replace('}', "}\n")
print(data2)
# ------- EDIT LIST END -----------
if sys.argv[1] == 'editlistcolor':
# ------- EDIT LIST COLOR START -----------
boardid = sys.argv[2]
listid = sys.argv[3]
newcolor = sys.argv[4]
valid_colors = ['white', 'green', 'yellow', 'orange', 'red', 'purple', 'blue', 'sky', 'lime', 'pink', 'black',
'silver', 'peachpuff', 'crimson', 'plum', 'darkgreen', 'slateblue', 'magenta', 'gold', 'navy',
'gray', 'saddlebrown', 'paleturquoise', 'mistyrose', 'indigo']
if newcolor not in valid_colors:
print("Invalid color. Choose a color from the list.")
sys.exit(1)
edlist = wekanurl + apiboards + boardid + s + l + s + listid
print(edlist)
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
put_data = {'color': '{}'.format(newcolor)}
body = requests.put(edlist, data=put_data, headers=headers)
print("=== EDIT LIST COLOR ===\n")
body = requests.get(edlist, headers=headers)
data2 = body.text.replace('}', "}\n")
print(data2)
# ------- EDIT LIST COLOR END -----------
if sys.argv[1] == 'newuser':
# ------- CREATE NEW USER START -----------
@@ -15,6 +15,20 @@
.reactions-popup .add-comment-reaction:hover {
background-color: #b0c4de;
}
/* Eye / eye-slash icon toggle for showing/hiding activities. Open eye
(.eye-icon) = activities shown; crossed eye (.eye-slash-icon) = hidden.
Matches the password-visibility toggle used on the login/register pages. */
.activities-eye-toggle {
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 0.4em;
text-decoration: none;
}
.activities-eye-toggle .eye-icon,
.activities-eye-toggle .eye-slash-icon {
line-height: 1;
}
.activities {
clear: both;
}
+5 -2
View File
@@ -106,10 +106,10 @@ template(name="activity")
//- comment activity ----------------------------------------------------
if($eq activity.activityType 'deleteComment')
| {{{_ 'activity-deleteComment' activity.commentId}}}.
| {{{_ 'activity-deleteComment' (sanitize activity.commentDisplayText)}}}.
if($eq activity.activityType 'editComment')
| {{{_ 'activity-editComment' activity.commentId}}}.
| {{{_ 'activity-editComment' (sanitize activity.commentDisplayText)}}}.
if($eq activity.activityType 'addComment')
| {{{_ 'activity-on' cardLink}}}
@@ -133,6 +133,9 @@ template(name="activity")
if($eq activity.activityType 'a-changedTitle')
| {{{_ 'activity-changedTitle' (sanitize activity.value) cardLink}}}.
if($eq activity.activityType 'a-changedDescription')
| {{{_ 'activity-changedDescription' cardLink}}}.
//- customField activity ------------------------------------------------
if($eq activity.activityType 'createCustomField')
| {{_ 'activity-customfield-created' customField}}.
+30 -3
View File
@@ -6,11 +6,13 @@ import '/client/lib/dragscrollTouch';
import { boardConverter } from '/client/lib/boardConverter';
import { formatDateByUserPreference } from '/imports/lib/dateUtils';
import { toFullCalendarFirstDay } from '/client/lib/calendarFirstDay';
import { weekNumberByFirstDay } from '/models/lib/weekStart';
import Swimlanes from '/models/swimlanes';
import Lists from '/models/lists';
import TableVisibilityModeSettings from '/models/tableVisibilityModeSettings';
import { EscapeActions } from '/client/lib/escapeActions';
import { Utils } from '/client/lib/utils';
import { Filter } from '/client/lib/filter';
// SubsManager removed for Meteor 3 migration
const { calculateIndex } = Utils;
@@ -578,7 +580,15 @@ Template.boardBody.onRendered(function () {
});
dragscroll.reset();
Utils.setBackgroundImage();
// #4978: apply the board background inside a reactive autorun instead of a
// one-shot call. Switching directly between boards (e.g. the favorites bar)
// reuses this template instance and never re-fires onRendered, so the
// background used to stay on the previously shown board. Reading the current
// board inside setBackgroundImage() tracks both board switches and background
// edits; it performs no DB writes, so there is no autorun write loop.
this.autorun(() => {
Utils.setBackgroundImage();
});
});
Template.boardBody.onDestroyed(function () {
@@ -929,6 +939,11 @@ Template.calendarView.onRendered(function () {
document.documentElement.dir = TAPi18n.getLanguageDirection();
this.autorun(function () {
// #5656: refetch calendar events whenever the active board Filter changes
// so the Calendar view stays in sync with the other views. Reading the
// Filter's reactive state here establishes the dependency; the events()
// callback below applies the actual selector.
Filter.isActive();
const calendarEl = document.getElementById('calendar-view');
if (calendarEl && calendarEl._wekanCalendar) {
calendarEl._wekanCalendar.refetchEvents();
@@ -959,6 +974,12 @@ Template.calendarView.helpers({
editable: true,
selectable: true,
weekNumbers: true,
// #4946: FullCalendar's default weekNumberCalculation is locale-based
// (Sunday-anchored for many locales), so the week-number column ignored
// the user's start-day-of-week setting even though `firstDay` moved the
// grid. Compute the number from the SAME firstDay so the label matches the
// way the week is laid out.
weekNumberCalculation: date => weekNumberByFirstDay(date, firstDay),
// Use non-localized AM/PM time format to avoid confusing notations like 上/下/中
// Use full 'am'/'pm' instead of single-letter 'a'/'p' for clarity
eventTimeFormat: {
@@ -1002,6 +1023,12 @@ Template.calendarView.helpers({
isRTL: TAPi18n.isRTL(),
events(fetchInfo, callback) {
const currentBoard = Utils.getCurrentBoard();
// #5656: apply the active board Filter (member / assignee / due-date /
// label / custom-field) so the Calendar view shows the same scoped set
// of cards as the Board / Lists / Swimlanes views.
const filterSelector = Filter.isActive()
? Filter._getMongoSelector()
: undefined;
const events = [];
const pushEvent = function (card, title, start, end, extraCls) {
start = start || card.startAt;
@@ -1026,12 +1053,12 @@ Template.calendarView.helpers({
});
};
currentBoard
.cardsInInterval(fetchInfo.start, fetchInfo.end)
.cardsInInterval(fetchInfo.start, fetchInfo.end, filterSelector)
.forEach(function (card) {
pushEvent(card);
});
currentBoard
.cardsDueInBetween(fetchInfo.start, fetchInfo.end)
.cardsDueInBetween(fetchInfo.start, fetchInfo.end, filterSelector)
.forEach(function (card) {
pushEvent(
card,
+7
View File
@@ -1078,6 +1078,13 @@ body.grey-icons-enabled .checkmark-no-grey {
margin: 8px; /* Space between board items */
}
/* #6439: highlight the board a dragged board will be dropped before, when
reordering in the Custom (drag order) sort mode. */
.js-board.board-reorder-over {
outline: 2px dashed #3498db;
outline-offset: 2px;
}
/* Reset background for add-board button */
.js-add-board {
background-color: transparent !important;
+62
View File
@@ -6,6 +6,10 @@ import TableVisibilityModeSettings from '/models/tableVisibilityModeSettings';
import { BoardMultiSelection } from '/client/lib/boardMultiSelection';
import { EscapeActions } from '/client/lib/escapeActions';
import { Utils } from '/client/lib/utils';
import {
isDragReorderEnabled,
computeReorderedSortIndex,
} from '/models/lib/boardSortReorder';
// SubsManager removed for Meteor 3 migration
@@ -59,6 +63,15 @@ const DEFAULT_WORKSPACE_ICON = '📁';
// Matches the Admin Panel > People page size.
const BOARDS_PER_PAGE = 25;
// #6439: the effective All Boards sort mode for the current user, defaulting to
// 'custom' (manual drag order) when unknown. Used to gate board drag-reordering.
function currentAllBoardsSortBy() {
const cu = ReactiveCache.getCurrentUser();
return cu && typeof cu.getAllBoardsSortBy === 'function'
? cu.getAllBoardsSortBy()
: 'custom';
}
function getCurrentWorkspacesTree() {
const currentUser = ReactiveCache.getCurrentUser();
const tree =
@@ -973,6 +986,55 @@ Template.boardList.events({
document.querySelectorAll('.workspace-node.board-drag-hint, .js-select-menu.board-drag-hint').forEach((el) => {
el.classList.remove('board-drag-hint');
});
document.querySelectorAll('.js-board.board-reorder-over').forEach((el) => {
el.classList.remove('board-reorder-over');
});
},
// #6439: reorder boards on the All Boards page by dropping one board onto
// another. Only active in the "custom" (manual drag order) sort mode — in the
// sorted modes the order comes from the title, so a board is not a valid drop
// target (which is why, before this, the browser showed the not-allowed cursor
// and nothing persisted). The reorder decision/index math lives in the pure,
// unit-tested models/lib/boardSortReorder.js.
'dragover .js-board'(evt, tpl) {
if (!isDragReorderEnabled(currentAllBoardsSortBy())) return;
// A multi-board drag is a share/assign gesture, not a reorder.
const dt = evt.originalEvent.dataTransfer;
if (dt && dt.getData('application/x-board-multi') === 'true') return;
evt.preventDefault();
evt.stopPropagation();
if (dt) dt.dropEffect = 'move';
evt.currentTarget.classList.add('board-reorder-over');
},
'dragleave .js-board'(evt) {
evt.currentTarget.classList.remove('board-reorder-over');
},
'drop .js-board'(evt, tpl) {
if (!isDragReorderEnabled(currentAllBoardsSortBy())) return;
const dt = evt.originalEvent.dataTransfer;
if (dt && dt.getData('application/x-board-multi') === 'true') return;
const draggedId = dt ? dt.getData('text/plain') : '';
if (!draggedId) return;
evt.preventDefault();
evt.stopPropagation();
evt.currentTarget.classList.remove('board-reorder-over');
const targetId = this._id;
// #6442: current display order of the board grid. Read each board's _id from
// its Blaze data context (the same source dragstart uses via `this._id`) —
// NOT el.classList[0]. On `li.js-board(class="{{_id}} …")` Jade emits the
// literal `js-board` class FIRST, so classList[0] is the string "js-board"
// for every board; the old code therefore produced ['js-board','js-board',…],
// computeReorderedSortIndex could not find the dragged/target ids among them,
// returned null, and the drop silently did nothing (board snapped back).
const orderedIds = Array.from(tpl.findAll('.js-board'))
.map((el) => Blaze.getData(el)?._id)
.filter(Boolean);
const mapping = computeReorderedSortIndex(orderedIds, draggedId, targetId);
if (!mapping) return;
const currentUser = ReactiveCache.getCurrentUser();
if (currentUser && typeof currentUser.setBoardSortIndexes === 'function') {
currentUser.setBoardSortIndexes(mapping);
}
},
'click .js-clone-board'(evt) {
if (confirm(TAPi18n.__('duplicate-board-confirm'))) {
+1 -1
View File
@@ -66,7 +66,7 @@ template(name="tableView")
td.table-view-cell-labels
.div
each label in row.labels
span.card-label(class="card-label-{{label.color}}" title="{{label.name}}")
span.card-label(class="{{labelColorClass label.color}}" style="{{labelColorStyle label.color}}" title="{{label.name}}")
+viewer
= label.name
if showReceivedColumn
+12 -8
View File
@@ -6,7 +6,7 @@ template(name="cardDetails")
+attachmentViewer
section.card-details.js-card-details.nodragscroll(class='{{#if cardMaximized}}card-details-maximized{{/if}}' class='{{#if isPopup}}card-details-popup{{/if}}' class='{{#unless isVerticalScrollbars}}no-scrollbars{{/unless}}' class='{{#if cardCollapsed}}card-details-collapsed{{/if}}'): .card-details-canvas
.card-details-header(class='{{#if colorClass}}card-details-{{colorClass}}{{/if}}')
.card-details-header(class='{{#if colorClass}}card-details-{{colorClass}}{{/if}}' style='{{colorStyle}}')
+inlinedForm(classNames="js-card-details-title")
+editCardTitleForm
else
@@ -127,7 +127,7 @@ template(name="cardDetails")
| {{_ 'labels'}}
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
each labels
span.card-label(class="card-label-{{color}}" title=name)
span.card-label(class="{{labelColorClass color}}" style="{{labelColorStyle color}}" title=name)
+viewer
= name
if canModifyCard
@@ -741,12 +741,12 @@ template(name="cardDetails")
i.fa.fa-history
| {{ _ 'activities'}}
if currentUser.isBoardMember
.material-toggle-switch(title="{{_ 'show-activities'}}")
if showActivities
input.toggle-switch(type="checkbox" id="toggleShowActivitiesCard" checked="checked")
else
input.toggle-switch(type="checkbox" id="toggleShowActivitiesCard")
label.toggle-label(for="toggleShowActivitiesCard")
if showActivities
a.activities-eye-toggle.js-toggle-show-activities-card(title="{{_ 'hide-activities'}}" aria-label="{{_ 'hide-activities'}}")
i.fa.fa-eye.eye-icon
else
a.activities-eye-toggle.js-toggle-show-activities-card(title="{{_ 'show-activities'}}" aria-label="{{_ 'show-activities'}}")
i.fa.fa-eye-slash.eye-slash-icon
if currentUser.isBoardAdmin
if isLoaded.get
@@ -1199,6 +1199,10 @@ template(name="setCardColorPopup")
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
if(isSelected color)
i.fa.fa-check
// #5514: native color wheel for picking a custom RGB / hex color
.color-wheel-wrap
label(for="cardColorWheel") {{_ 'custom-color'}}
input.js-card-color-wheel#cardColorWheel(type="color" value=currentColorHex title="{{_ 'custom-color'}}")
button.primary.confirm.js-submit {{_ 'save'}}
button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
+19 -4
View File
@@ -50,8 +50,10 @@ import Users from '/models/users';
import Lists from '/models/lists';
import CardComments from '/models/cardComments';
import { ALLOWED_COLORS } from '/config/const';
import { isHexColor, toHex } from '/models/lib/contrastColor';
import { uniqBy } from '/imports/lib/collectionHelpers';
import { memberTargetBoardId } from '/models/lib/linkedCardMembers';
import { isSubmitKey } from '/models/lib/editorSubmitKey';
import { UserAvatar } from '../users/userAvatar';
import { Filter } from '/client/lib/filter';
import { BoardSwimlaneListCardDialog } from '/client/lib/dialogWithBoardSwimlaneListCard';
@@ -1046,7 +1048,7 @@ Template.cardDetails.events({
const card = Template.currentData();
await card.toggleHideCheckedChecklistItems();
},
async 'change #toggleShowActivitiesCard'() {
async 'click .js-toggle-show-activities-card'() {
const card = Template.currentData();
await card.toggleShowActivities();
},
@@ -1498,9 +1500,11 @@ Template.editCardTitleForm.events({
Utils.showCopied(promise, $tooltip);
},
'keydown .js-edit-card-title'(event) {
// If enter key was pressed, submit the data
// Unless the shift key is also being pressed
if (event.keyCode === 13 && !event.shiftKey) {
// #4236: match the card description field — Ctrl/Cmd+Enter saves; plain
// Enter (and Shift+Enter) insert a new line instead of submitting. The old
// handler submitted on any Enter without Shift, so Enter could not add a
// newline in the title.
if (isSubmitKey(event)) {
$('.js-submit-edit-card-title-form').click();
}
},
@@ -2032,6 +2036,10 @@ Template.setCardColorPopup.helpers({
}
return tpl.currentColor.get() === color;
},
// #5514: current color as a '#rrggbb' hex for the native color wheel <input>.
currentColorHex() {
return toHex(Template.instance().currentColor.get()) || '#0079bf';
},
});
Template.setCardColorPopup.events({
@@ -2039,6 +2047,13 @@ Template.setCardColorPopup.events({
const paletteData = Blaze.getData(event.currentTarget);
tpl.currentColor.set(paletteData?.color);
},
// #5514: picking from the native color wheel stores a custom hex.
'input .js-card-color-wheel'(event, tpl) {
const value = event.currentTarget.value;
if (isHexColor(value)) {
tpl.currentColor.set(value);
}
},
async 'click .js-submit'(event, tpl) {
event.preventDefault();
const card = Cards.findOne(getCardId());
+21
View File
@@ -1,3 +1,24 @@
/* #5514: native color-wheel (custom RGB / hex) picker wrapper, shared by the
label / list / swimlane / card color popups. */
.color-wheel-wrap {
display: flex;
align-items: center;
gap: 8px;
margin: 6px 0 10px 0;
}
.color-wheel-wrap label {
margin: 0;
}
.color-wheel-wrap input[type="color"] {
width: 44px;
height: 28px;
padding: 0;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
background: none;
}
.card-label {
border: 1px solid #000;
border-radius: 4px;
+6 -3
View File
@@ -4,9 +4,12 @@ template(name="formLabel")
label {{_ "select-color"}}
.palette-colors: each labels
span.card-label.palette-color.js-palette-color(class="card-label-{{color}}")
span.card-label.palette-color.js-palette-color(class="{{labelColorClass color}}" style="{{labelColorStyle color}}")
if(isSelected color)
i.fa.fa-check
.color-wheel-wrap
label(for="labelColorWheel") {{_ 'custom-color'}}
input.js-label-color-wheel#labelColorWheel(type="color" value=currentColorHex title="{{_ 'custom-color'}}")
template(name="createLabelPopup")
form.create-label
@@ -31,8 +34,8 @@ template(name="cardLabelsPopup")
a.card-label-edit-button.fa.fa-pencil.js-edit-label
if isTouchScreenOrShowDesktopDragHandles
span.fa.label-handle(class="fa-arrows" title="{{_ 'dragLabel'}}")
span.card-label.card-label-selectable.js-select-label.card-label-wrapper(class="card-label-{{color}}"
class="{{# if isLabelSelected ../_id }}active{{/if}}")
span.card-label.card-label-selectable.js-select-label.card-label-wrapper(class="{{labelColorClass color}}"
class="{{# if isLabelSelected ../_id }}active{{/if}}" style="{{labelColorStyle color}}")
+viewer
= name
if(isLabelSelected ../_id)
+33 -2
View File
@@ -1,5 +1,6 @@
import { ReactiveCache } from '/imports/reactiveCache';
import { LABEL_COLORS } from '/models/metadata/colors';
import { isHexColor, toHex } from '/models/lib/contrastColor';
import { EscapeActions } from '/client/lib/escapeActions';
import { Utils } from '/client/lib/utils';
@@ -28,6 +29,11 @@ Template.formLabel.helpers({
isSelected(color) {
return Template.instance().currentColor.get() === color;
},
// #5514: current color as a '#rrggbb' hex for the color-wheel <input>, which
// only accepts hex. Named colors map to their palette hex; fall back to green.
currentColorHex() {
return toHex(Template.instance().currentColor.get()) || '#3cb500';
},
});
Template.formLabel.events({
@@ -36,6 +42,13 @@ Template.formLabel.events({
const selectedColor = paletteData?.color || Template.currentData()?.color || getFallbackLabelColor();
tpl.currentColor.set(selectedColor);
},
// #5514: picking a color from the native color wheel stores a custom hex.
'input .js-label-color-wheel'(event, tpl) {
const value = event.currentTarget.value;
if (isHexColor(value)) {
tpl.currentColor.set(value);
}
},
});
Template.createLabelPopup.helpers({
@@ -131,7 +144,16 @@ Template.createLabelPopup.events({
? selectedColorIcon.closest('.js-palette-color')
: null;
const selectedColorData = selectedPaletteNode && Blaze.getData(selectedPaletteNode);
const color = selectedColorData?.color || getFallbackLabelColor();
// #5514: a named swatch (has the check icon) wins; otherwise fall back to
// the custom color-wheel hex, then to the default palette color.
let color = selectedColorData?.color;
if (!color) {
const wheel = templateInstance.find('.js-label-color-wheel');
if (wheel && isHexColor(wheel.value)) {
color = wheel.value;
}
}
color = color || getFallbackLabelColor();
board.addLabel(name, color);
Popup.back();
},
@@ -158,7 +180,16 @@ Template.editLabelPopup.events({
? selectedColorIcon.closest('.js-palette-color')
: null;
const selectedColorData = selectedPaletteNode && Blaze.getData(selectedPaletteNode);
const color = selectedColorData?.color || getFallbackLabelColor();
// #5514: a named swatch (has the check icon) wins; otherwise fall back to
// the custom color-wheel hex, then to the default palette color.
let color = selectedColorData?.color;
if (!color) {
const wheel = templateInstance.find('.js-label-color-wheel');
if (wheel && isHexColor(wheel.value)) {
color = wheel.value;
}
}
color = color || getFallbackLabelColor();
board.editLabel(this._id, name, color);
Popup.back();
},
+11
View File
@@ -183,6 +183,13 @@
}
.minicard .minicard-title {
margin-inline-end: 1.5vw;
/* #6444: isolate each title's bidirectional context. The title is a
dir="auto" .viewer; under a global dir="rtl" document, non-isolated
dir="auto" runs share bidi state, so typing a strong RTL (e.g. Arabic)
character into another list's dir="auto" composer re-resolved the shared
context and visibly reflowed OTHER lists' minicard titles (no data change,
reverts on refresh). Isolation makes each title a self-contained run. */
unicode-bidi: isolate;
}
.minicard .minicard-title .card-number {
color: #b3b3b3;
@@ -448,6 +455,10 @@
min-height: 50px;
margin-bottom: 20px;
overflow-y: auto;
/* #6444: isolate the composer's dir="auto" bidi run so typing a strong RTL
character here cannot perturb the rendering of the surrounding minicard
titles under a dir="rtl" document. */
unicode-bidi: isolate;
}
.parent-prefix {
color: #b3b3b3;
+4 -3
View File
@@ -3,7 +3,8 @@ template(name="minicard")
class="{{#if isLinkedCard}}linked-card{{/if}}"
class="{{#if isLinkedBoard}}linked-board{{/if}}"
class="{{agingClass}}"
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}")
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}"
style="{{colorStyle}}")
if canMoveCard
if isTouchScreenOrShowDesktopDragHandles
.handle
@@ -93,11 +94,11 @@ template(name="minicard")
.minicard-labels(class="{{#if hiddenMinicardLabelText}}minicard-labels-no-text{{/if}}")
each labels
unless hiddenMinicardLabelText
span.js-card-label.card-label(class="card-label-{{color}}" title=name)
span.js-card-label.card-label(class="{{labelColorClass color}}" style="{{labelColorStyle color}}" title=name)
+viewer
= name
if hiddenMinicardLabelText
.minicard-label(class="card-label-{{color}}" title="{{name}}")
.minicard-label(class="{{labelColorClass color}}" style="{{labelColorStyle color}}" title="{{name}}")
.minicard-custom-fields
each customFieldsWD
+49 -17
View File
@@ -6,6 +6,11 @@ import uploadProgressManager from '../../lib/uploadProgressManager';
import { Utils } from '/client/lib/utils';
import ChecklistItems from '/models/checklistItems';
import Cards from '/models/cards';
import { resolveCoverId } from '/models/lib/linkedCardCover';
import {
parseChecklistItemTitles,
buildChecklistItemPayload,
} from '/models/lib/checklistItemTitles';
import { normalizeDependencies } from '/models/metadata/dependencies';
function getMinicardFlag(board, onMinicardField, legacyField, defaultValue) {
@@ -164,8 +169,12 @@ Template.minicard.helpers({
}
},
cover() {
if (!this.coverId) return null;
const attachment = ReactiveCache.getAttachment(this.coverId);
// #5666: for a linked card the cover lives on the real card it points at, so
// resolve the cover id through it (mirroring getTitle/getDue/...); a plain
// card resolves to its own coverId.
const coverId = resolveCoverId(this, id => ReactiveCache.getCard(id));
if (!coverId) return null;
const attachment = ReactiveCache.getAttachment(coverId);
if (!attachment) return null;
const coverLink = typeof attachment.link === 'function' ? attachment.link() : '';
if (!coverLink) return null;
@@ -376,6 +385,28 @@ Template.minicardChecklist.helpers({
},
});
// #6440: create the checklist item(s) for the minicard add-item form. Shared by
// the Save-button click handler and the (rarely reached) form-submit handler.
// The Save button needs an explicit click handler because the minicard — and so
// the add-item <form> — is rendered inside the `a.minicard-wrapper` anchor, where
// the native form `submit` event never reaches the Blaze event map; without this
// the "+" add-item on the minicard did nothing. The blank-input guard and the
// title parsing live in the pure, unit-tested models/lib/checklistItemTitles.js.
function addMinicardChecklistItems(textarea, checklist) {
if (!textarea || !checklist) return;
const titles = parseChecklistItemTitles(textarea.value);
if (titles.length === 0) return;
const items = checklist.items();
const lastItem = items[items.length - 1] || null;
let sortIndex = Utils.calculateIndexData(lastItem, null).base;
titles.forEach(title => {
ChecklistItems.insert(buildChecklistItemPayload(title, checklist, sortIndex));
sortIndex += 1;
});
textarea.value = '';
textarea.focus();
}
Template.minicardChecklist.events({
'click .js-convert-checklist-item-to-card'(event) {
event.stopPropagation();
@@ -417,25 +448,26 @@ Template.minicardChecklist.events({
}
$form.find('.js-close-inlined-form').trigger('click');
},
// #6440: explicit click handler for the minicard "+" add-item Save button.
// The native form `submit` event does not fire on the minicard (the form is
// inside the `a.minicard-wrapper` anchor), so — unlike card-detail — we cannot
// rely on `submit .js-add-checklist-item`. This mirrors the already-working
// `click .js-submit-edit-checklist-item-form` above.
'click .js-submit-add-checklist-item-form'(event) {
event.preventDefault();
event.stopPropagation();
const $form = $(event.currentTarget).closest('form');
const textarea = $form.find('textarea.js-add-checklist-item')[0];
const formData = Blaze.getData($form[0]) || Template.currentData() || {};
addMinicardChecklistItems(textarea, formData.checklist);
},
// Kept for completeness (e.g. card-detail-style contexts); on the minicard this
// rarely fires, so the click handler above is the real path. See #6440.
'submit .js-add-checklist-item'(event, tpl) {
event.preventDefault();
const textarea = tpl.find('textarea.js-add-checklist-item');
if (!textarea) return;
const title = textarea.value.trim();
const data = Template.currentData() || {};
const checklist = data.checklist;
if (!checklist || !title) return;
const items = checklist.items();
const lastItem = items[items.length - 1] || null;
const sortIndex = Utils.calculateIndexData(lastItem, null).base;
ChecklistItems.insert({
title,
checklistId: checklist._id,
cardId: checklist.cardId,
sort: sortIndex,
});
textarea.value = '';
textarea.focus();
addMinicardChecklistItems(textarea, data.checklist);
},
'click .js-delete-checklist-item': Popup.afterConfirm('checklistItemDelete', function () {
Popup.back();
+20 -1
View File
@@ -736,9 +736,28 @@ form.inlined-form .list-composer {
flex: 1 1 auto;
flex-direction: column;
display: flex;
overflow-y: auto;
/* #5439: always show a scrollbar on the list body across desktop and mobile
browsers (overlay scrollbars on macOS/iOS/Android/Firefox otherwise auto-
hide it). Keep these declarations in sync with models/lib/scrollbarCss.js
(alwaysVisibleScrollbarCss), which is unit tested. */
overflow-y: scroll;
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.35) rgba(0, 0, 0, 0.08);
scrollbar-gutter: stable;
padding: 5px 11px;
}
.list-body::-webkit-scrollbar {
width: 10px;
height: 10px;
-webkit-appearance: none;
}
.list-body::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.08);
}
.list-body::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.35);
border-radius: 5px;
}
.list-body .minicards {
flex-grow: 1;
flex-shrink: 0;
+1 -1
View File
@@ -46,7 +46,7 @@ template(name="addCardForm")
if getLabels
.minicard-labels
each getLabels
.minicard-label(class="card-label-{{color}}" title="{{name}}")
.minicard-label(class="{{labelColorClass color}}" style="{{labelColorStyle color}}" title="{{name}}")
textarea.minicard-composer-textarea.js-card-title(autofocus dir="auto")
if members.get
.minicard-members.js-minicard-composer-members
+20 -14
View File
@@ -10,6 +10,8 @@ import { Filter } from '/client/lib/filter';
import { MultiSelection } from '/client/lib/multiSelection';
import { Utils } from '/client/lib/utils';
import { isLinkableCardTarget } from '/models/lib/linkedCardTarget';
import { listCardsSelector } from '/models/lib/swimlaneFilter';
import { sortCardsByTitle } from '/models/lib/sortCardsByTitle';
import autosize from 'autosize';
// SubsManager removed for Meteor 3 migration
@@ -339,19 +341,21 @@ Template.listBody.helpers({
if (!sortBy) {
sortBy = defaultSort;
}
const selector = {
listId: Template.currentData()._id,
archived: false,
};
if (swimlaneId) {
// Fallback: also show cards with no swimlaneId (null/empty) so that
// pre-migration / orphaned cards are always visible without a DB migration.
selector.$or = [
{ swimlaneId },
{ swimlaneId: null }, // null covers null AND missing field
{ swimlaneId: '' }, // empty string from shared-lists era
];
}
// #6441: build the swimlane-membership fallback as a single `swimlaneId:
// { $in: [...] }` clause (via the shared, unit-tested helper) instead of a
// bare top-level `$or`, so it never competes with the board Filter's own
// top-level `$or` (labels/members/exceptions) and the label filter applies
// board-wide across every swimlane.
// #6443: in the first swimlane also surface orphaned cards (a swimlaneId
// pointing at a deleted swimlane) so they are not invisible in swimlane view.
const list = Template.currentData();
const selector = listCardsSelector(
list._id,
swimlaneId,
list.orphanedCardsSwimlaneIds
? list.orphanedCardsSwimlaneIds(swimlaneId)
: undefined,
);
const ret = ReactiveCache.getCards(Filter.mongoSelector(selector), {
// sort: ['sort'],
sort: sortBy,
@@ -717,7 +721,9 @@ Template.linkCardPopup.helpers({
if (tpl.selectedListId.get()) selector.listId = tpl.selectedListId.get();
const ret = ReactiveCache.getCards(selector, { sort: { sort: 1 } });
return ret;
// #5394: sort the Cards dropdown alphabetically by title
// (case-insensitive) so a card can be found on boards with many cards.
return sortCardsByTitle(ret);
},
isTitleDefault(title) {
+6 -1
View File
@@ -1,7 +1,8 @@
template(name="listHeader")
.list-header.js-list-header.nodragscroll(
class="{{#if limitToShowCardsCount}}list-header-card-count{{/if}}"
class=colorClass)
class=colorClass
style=colorStyle)
//- #459: keyboard/screen-reader list reordering (visually hidden, focusable).
.list-move-buttons.sr-only
a.js-list-move-left(href="#" role="button" aria-label="{{_ 'move-list-left'}}") {{_ 'move-list-left'}}
@@ -279,6 +280,10 @@ template(name="setListColorPopup")
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
if(isSelected color)
i.fa.fa-check
// #5514: native color wheel for picking a custom RGB / hex color
.color-wheel-wrap
label(for="listColorWheel") {{_ 'custom-color'}}
input.js-list-color-wheel#listColorWheel(type="color" value=currentColorHex title="{{_ 'custom-color'}}")
button.primary.confirm.js-submit {{_ 'save'}}
button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
+12
View File
@@ -5,6 +5,7 @@ import dragscroll from '@wekanteam/dragscroll';
import { BoardSwimlaneListDialog } from '/client/lib/dialogWithBoardSwimlaneList';
import Cards from '/models/cards';
import { LIST_COLORS } from '/models/metadata/colors';
import { isHexColor, toHex } from '/models/lib/contrastColor';
import { MultiSelection } from '/client/lib/multiSelection';
import { Utils } from '/client/lib/utils';
@@ -476,6 +477,10 @@ Template.setListColorPopup.helpers({
return tpl.currentColor.get() === color;
}
},
// #5514: current color as a '#rrggbb' hex for the native color wheel <input>.
currentColorHex() {
return toHex(Template.instance().currentColor.get()) || '#0079bf';
},
});
Template.setListColorPopup.events({
@@ -483,6 +488,13 @@ Template.setListColorPopup.events({
const paletteData = Blaze.getData(event.currentTarget);
tpl.currentColor.set(paletteData?.color);
},
// #5514: picking from the native color wheel stores a custom hex.
'input .js-list-color-wheel'(event, tpl) {
const value = event.currentTarget.value;
if (isHexColor(value)) {
tpl.currentColor.set(value);
}
},
async 'submit form'(event, tpl) {
event.preventDefault();
try {
+9
View File
@@ -83,14 +83,23 @@ Template.userFormsLayout.onRendered(() => {
})();
});
// #4394 (security): a one-shot $('.at-signup-link').hide() does not survive
// the useraccounts form re-rendering that happens after a failed login (e.g.
// an LDAP "User not Found") — the links were recreated without the inline
// display:none and reappeared even though registration / forgot-password
// were disabled in the Admin Panel. Toggle a class on the stable <body>
// ancestor and hide the links via CSS (userForm.css) so the rule keeps
// applying to every freshly re-rendered copy of the links.
Meteor.call('isDisableRegistration', (_, result) => {
if (result) {
document.body.classList.add('registration-disabled');
$('.at-signup-link').hide();
}
});
Meteor.call('isDisableForgotPassword', (_, result) => {
if (result) {
document.body.classList.add('forgotpwd-disabled');
$('.at-pwd-link').hide();
}
});
+1 -1
View File
@@ -94,7 +94,7 @@ template(name="myCards")
td
.div
each label in card.labelIds
span.card-label(class="card-label-{{labelColor board label}}" title=name)
span.card-label(class="{{labelColorClass (labelColor board label)}}" style="{{labelColorStyle (labelColor board label)}}" title=name)
| {{labelName board label}}
td
if card.dueAt
+17 -40
View File
@@ -106,38 +106,19 @@ Template.boardActions.events({
const boardId = Session.get('currentBoard');
const destBoardId = tpl.find('#board-id').value;
const desc = Utils.getTriggerActionDesc(event, tpl);
if (actionSelected === 'top') {
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'moveCardToTop',
listName,
swimlaneName,
boardId: destBoardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
}
if (actionSelected === 'bottom') {
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'moveCardToBottom',
listName,
swimlaneName,
boardId: destBoardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
}
// #5536: create the rule on the server (see server/rulesButton.js →
// rules.createRule) instead of three optimistic client Collection.insert()
// calls. The optimistic writes landed in minimongo limbo once the wizard
// subscription stopped, so the cross-board move action rendered BLANK; and
// the client allow/deny rules rejected them outright for non-owner members.
// The action keeps its own destination `boardId` (the board to move to).
Meteor.call('rules.createRule', boardId, ruleName, trigger, {
actionType: actionSelected === 'bottom' ? 'moveCardToBottom' : 'moveCardToTop',
listName,
swimlaneName,
boardId: destBoardId,
desc,
});
},
'click .js-add-gen-move-action'(event, tpl) {
const desc = Utils.getTriggerActionDesc(event, tpl);
@@ -203,20 +184,16 @@ Template.boardActions.events({
const boardId = Session.get('currentBoard');
const destBoardId = tpl.find('#board-id-link').value;
const desc = Utils.getTriggerActionDesc(event, tpl);
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
// #5536: create on the server so the cross-board link action does not land
// blank in minimongo limbo / get rejected by client allow/deny. The action
// keeps its own destination `boardId` (the board to link the card into).
Meteor.call('rules.createRule', boardId, ruleName, trigger, {
actionType: 'linkCard',
listName,
swimlaneName,
boardId: destBoardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
},
'click .js-sort-list-action'(event, tpl) {
const data = Template.currentData();
@@ -100,8 +100,15 @@ template(name="cardActions")
option(value="receivedAt") {{_'r-df-received-at'}}
div.trigger-dropdown
input(id="reldate-days",type="number",value="0")
div.trigger-dropdown
select(id="reldate-unit")
option(value="minutes") {{_'r-unit-minutes'}}
option(value="hours") {{_'r-unit-hours'}}
option(value="days",selected="selected") {{_'r-unit-days'}}
option(value="weeks") {{_'r-unit-weeks'}}
option(value="months") {{_'r-unit-months'}}
div.trigger-text
| {{_'r-days-after'}}
| {{_'r-later'}}
div.trigger-button.js-set-reldate-action.js-goto-rules
i.fa.fa-plus
@@ -238,12 +238,16 @@ Template.cardActions.events({
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, tpl);
const dateField = tpl.find('#reldate-datefield').value;
// `days` keeps its name for backward compatibility: it is the numeric
// amount, interpreted together with `unit` (minutes/hours/days/weeks/months).
const days = parseInt(tpl.find('#reldate-days').value, 10) || 0;
const unit = tpl.find('#reldate-unit').value;
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'setDateRelative',
dateField,
days,
unit,
boardId,
desc,
});
+4 -5
View File
@@ -1,7 +1,5 @@
import { ReactiveCache } from '/imports/reactiveCache';
import Actions from '/models/actions';
import Rules from '/models/rules';
import Triggers from '/models/triggers';
function boardRuleIds() {
const boardId = Session.get('currentBoard');
@@ -62,9 +60,10 @@ Template.rulesList.events({
getSelected().forEach(ruleId => {
const rule = ReactiveCache.getRule(ruleId);
if (rule) {
Rules.remove(rule._id);
Actions.remove(rule.actionId);
Triggers.remove(rule.triggerId);
// Delete the rule + its trigger + action server-side (see
// server/rulesButton.js `rules.deleteRule`): three client-side
// Collection.remove() calls were rejected with 403 "Access denied".
Meteor.call('rules.deleteRule', rule._id);
}
});
setSelected([]);
+6 -6
View File
@@ -1,9 +1,6 @@
import { ReactiveCache } from '/imports/reactiveCache';
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { Utils } from '/client/lib/utils';
import Actions from '/models/actions';
import Rules from '/models/rules';
import Triggers from '/models/triggers';
Template.rulesMain.onCreated(function () {
this.rulesCurrentTab = new ReactiveVar('rulesList');
@@ -83,9 +80,12 @@ function sanitizeObject(obj) {
Template.rulesMain.events({
'click .js-delete-rule'() {
const rule = Template.currentData();
Rules.remove(rule._id);
Actions.remove(rule.actionId);
Triggers.remove(rule.triggerId);
// Delete the rule + its trigger + action in one server call. Doing this
// client-side as three separate Collection.remove() calls failed with 403
// "Access denied" whenever a trigger/action document's boardId did not
// resolve to a board in the allow() rule; the method authorizes once and
// removes all three server-side.
Meteor.call('rules.deleteRule', rule._id);
},
'click .js-goto-trigger'(event, tpl) {
event.preventDefault();
+2 -2
View File
@@ -12,7 +12,7 @@ template(name="rulesWorkflow")
.workflow-node.workflow-node-when
span.workflow-node-label {{_ 'r-when'}}
span.workflow-node-text= builderTriggerLabel
a.workflow-slot-clear.js-clear-when(title="{{_ 'remove'}}") &#10005;
a.workflow-slot-clear.js-clear-when(title="{{_ 'r-remove'}}") &#10005;
else
span.workflow-slot-placeholder {{_ 'r-when'}}: {{_ 'r-drop-trigger'}}
.workflow-arrow
@@ -22,7 +22,7 @@ template(name="rulesWorkflow")
.workflow-node.workflow-node-then
span.workflow-node-label {{_ 'r-action'}}
span.workflow-node-text= builderActionLabel
a.workflow-slot-clear.js-clear-then(title="{{_ 'remove'}}") &#10005;
a.workflow-slot-clear.js-clear-then(title="{{_ 'r-remove'}}") &#10005;
else
span.workflow-slot-placeholder {{_ 'r-action'}}: {{_ 'r-drop-action'}}
.workflow-builder-controls
+46 -32
View File
@@ -12,31 +12,44 @@ import Triggers from '/models/triggers';
// can be built entirely by dragging. Parameterized rules (specific list, label,
// member, schedule time, …) are still created with the form builder on the
// List view.
// Each palette entry carries an i18n `labelKey` (translated at render time via
// TAPi18n.__) instead of a hardcoded English string, so the whole workflow view
// follows the UI language. `labelParams` is passed to TAPi18n.__ for labels that
// need a placeholder (e.g. the scheduled time). Existing rule keys are reused
// where they fit; workflow-only labels use new `r-w-*` keys (see en.i18n.json).
const TRIGGER_PALETTE = [
{ label: 'Card is created', doc: { activityType: 'createCard', listName: '*', swimlaneName: '*', cardTitle: '*', userId: '*' } },
{ label: 'Card is moved', doc: { activityType: 'moveCard', listName: '*', oldListName: '*', swimlaneName: '*', cardTitle: '*', userId: '*' } },
{ label: 'Card is archived', doc: { activityType: 'archivedCard', userId: '*' } },
{ label: 'Card is unarchived', doc: { activityType: 'restoredCard', userId: '*' } },
{ label: 'Any label is added', doc: { activityType: 'addedLabel', labelId: '*', userId: '*' } },
{ label: 'Any label is removed', doc: { activityType: 'removedLabel', labelId: '*', userId: '*' } },
{ label: 'A member is added', doc: { activityType: 'joinMember', username: '*', userId: '*' } },
{ label: 'A member is removed', doc: { activityType: 'unjoinMember', username: '*', userId: '*' } },
{ label: 'A checklist is added', doc: { activityType: 'addChecklist', checklistName: '*', userId: '*' } },
{ label: 'An attachment is added', doc: { activityType: 'addAttachment', userId: '*' } },
{ label: 'Every day at 09:00', doc: { activityType: 'scheduledTrigger', scheduleKind: 'calendar', scheduleType: 'daily', atTime: '09:00', listName: '*', swimlaneName: '*' } },
{ labelKey: 'r-w-card-created', doc: { activityType: 'createCard', listName: '*', swimlaneName: '*', cardTitle: '*', userId: '*' } },
{ labelKey: 'r-when-a-card-is-moved', doc: { activityType: 'moveCard', listName: '*', oldListName: '*', swimlaneName: '*', cardTitle: '*', userId: '*' } },
{ labelKey: 'r-w-card-archived', doc: { activityType: 'archivedCard', userId: '*' } },
{ labelKey: 'r-w-card-unarchived', doc: { activityType: 'restoredCard', userId: '*' } },
{ labelKey: 'r-w-label-added', doc: { activityType: 'addedLabel', labelId: '*', userId: '*' } },
{ labelKey: 'r-w-label-removed', doc: { activityType: 'removedLabel', labelId: '*', userId: '*' } },
{ labelKey: 'r-w-member-added', doc: { activityType: 'joinMember', username: '*', userId: '*' } },
{ labelKey: 'r-w-member-removed', doc: { activityType: 'unjoinMember', username: '*', userId: '*' } },
{ labelKey: 'r-w-checklist-added', doc: { activityType: 'addChecklist', checklistName: '*', userId: '*' } },
{ labelKey: 'r-w-attachment-added', doc: { activityType: 'addAttachment', userId: '*' } },
{ labelKey: 'r-w-every-day-at', labelParams: { time: '09:00' }, doc: { activityType: 'scheduledTrigger', scheduleKind: 'calendar', scheduleType: 'daily', atTime: '09:00', listName: '*', swimlaneName: '*' } },
];
const ACTION_PALETTE = [
{ label: 'Move card to top', doc: { actionType: 'moveCardToTop', listName: '*', swimlaneName: '*' } },
{ label: 'Move card to bottom', doc: { actionType: 'moveCardToBottom', listName: '*', swimlaneName: '*' } },
{ label: 'Archive card', doc: { actionType: 'archive' } },
{ label: 'Unarchive card', doc: { actionType: 'unarchive' } },
{ label: 'Mark card complete', doc: { actionType: 'markCardComplete' } },
{ label: 'Mark card incomplete', doc: { actionType: 'markCardIncomplete' } },
{ label: 'Remove all members', doc: { actionType: 'removeMember', username: '*' } },
{ label: 'Set received date to now', doc: { actionType: 'setDate', dateField: 'receivedAt' } },
{ labelKey: 'r-d-move-to-top-gen', doc: { actionType: 'moveCardToTop', listName: '*', swimlaneName: '*' } },
{ labelKey: 'r-d-move-to-bottom-gen', doc: { actionType: 'moveCardToBottom', listName: '*', swimlaneName: '*' } },
{ labelKey: 'r-d-archive', doc: { actionType: 'archive' } },
{ labelKey: 'r-d-unarchive', doc: { actionType: 'unarchive' } },
{ labelKey: 'r-mark-complete', doc: { actionType: 'markCardComplete' } },
{ labelKey: 'r-mark-incomplete', doc: { actionType: 'markCardIncomplete' } },
{ labelKey: 'r-remove-all', doc: { actionType: 'removeMember', username: '*' } },
{ labelKey: 'r-w-set-received-now', doc: { actionType: 'setDate', dateField: 'receivedAt' } },
];
// Translate a palette entry's label for display / storage in the current UI
// language (matches the classic Rules view, which also stores already-translated
// description text at creation time).
function paletteLabel(entry) {
if (!entry) return '';
return TAPi18n.__(entry.labelKey, entry.labelParams);
}
Template.rulesWorkflow.onCreated(function () {
this.builderTrigger = new ReactiveVar(null);
this.builderAction = new ReactiveVar(null);
@@ -52,24 +65,22 @@ Template.rulesWorkflow.helpers({
return Utils.getCurrentBoard();
},
triggerPalette() {
return TRIGGER_PALETTE.map((t, idx) => ({ idx, label: t.label }));
return TRIGGER_PALETTE.map((t, idx) => ({ idx, label: paletteLabel(t) }));
},
actionPalette() {
return ACTION_PALETTE.map((a, idx) => ({ idx, label: a.label }));
return ACTION_PALETTE.map((a, idx) => ({ idx, label: paletteLabel(a) }));
},
builderTrigger() {
return Template.instance().builderTrigger.get();
},
builderTriggerLabel() {
const t = Template.instance().builderTrigger.get();
return t ? t.label : '';
return paletteLabel(Template.instance().builderTrigger.get());
},
builderAction() {
return Template.instance().builderAction.get();
},
builderActionLabel() {
const a = Template.instance().builderAction.get();
return a ? a.label : '';
return paletteLabel(Template.instance().builderAction.get());
},
createDisabled() {
const tpl = Template.instance();
@@ -96,9 +107,11 @@ function persistRule(tpl) {
if (!t || !a) return;
const boardId = Session.get('currentBoard');
const titleField = tpl.find('.js-workflow-rule-title');
const title = (titleField.value || '').trim() || `${t.label} → ${a.label}`;
const triggerId = Triggers.insert({ ...t.doc, boardId, desc: t.label });
const actionId = Actions.insert({ ...a.doc, boardId, desc: a.label });
const tLabel = paletteLabel(t);
const aLabel = paletteLabel(a);
const title = (titleField.value || '').trim() || `${tLabel} → ${aLabel}`;
const triggerId = Triggers.insert({ ...t.doc, boardId, desc: tLabel });
const actionId = Actions.insert({ ...a.doc, boardId, desc: aLabel });
Rules.insert({ title, triggerId, actionId, boardId });
tpl.builderTrigger.set(null);
tpl.builderAction.set(null);
@@ -140,7 +153,7 @@ Template.rulesWorkflow.events({
const a = ACTION_PALETTE[tpl.dragItem.idx];
const boardId = Session.get('currentBoard');
const oldActionId = rule.actionId;
const newActionId = Actions.insert({ ...a.doc, boardId, desc: a.label });
const newActionId = Actions.insert({ ...a.doc, boardId, desc: paletteLabel(a) });
Rules.update(ruleId, { $set: { actionId: newActionId } });
if (oldActionId) Actions.remove(oldActionId);
tpl.dragItem = null;
@@ -163,8 +176,9 @@ Template.rulesWorkflow.events({
const ruleId = node && node.dataset.ruleId;
const rule = ReactiveCache.getRule(ruleId);
if (!rule) return;
Rules.remove(rule._id);
Actions.remove(rule.actionId);
Triggers.remove(rule.triggerId);
// Delete the rule + its trigger + action server-side (see
// server/rulesButton.js `rules.deleteRule`): three client-side
// Collection.remove() calls were rejected with 403 "Access denied".
Meteor.call('rules.deleteRule', rule._id);
},
});
+59
View File
@@ -378,3 +378,62 @@ table td:first-child {
.roles-settings .roles-description {
margin-bottom: 1rem;
}
/* Admin Panel > People > Domains table: search + column sort + pagination,
matching the Board Table view / other admin tables. */
.domain-controls {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 8px;
}
.domain-controls input.js-domain-search {
flex: 1 1 auto;
height: 30px;
padding: 0 8px;
border: 1px solid #bbb;
border-radius: 0.4vw;
}
.domain-controls button.js-domain-search-button {
height: 30px;
padding: 0 12px;
border: 1px solid #bbb;
background: #fff;
border-radius: 0.4vw;
cursor: pointer;
}
.domain-pagination {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 12px;
}
.domain-pagination button {
min-width: 32px;
height: 30px;
padding: 0 10px;
border: 1px solid #bbb;
background: #fff;
border-radius: 0.4vw;
cursor: pointer;
}
.domain-pagination button.disabled {
opacity: 0.5;
pointer-events: none;
}
.domain-page-info {
min-width: 72px;
text-align: center;
color: #333;
}
th.js-domain-sort {
cursor: pointer;
user-select: none;
}
+10 -3
View File
@@ -122,7 +122,7 @@ template(name="people")
else if templatesSetting.get
+templatesGeneral
else if domainSetting.get
+domainGeneral(domainList=domainList)
+domainGeneral
template(name="orgGeneral")
@@ -239,11 +239,18 @@ template(name="selectAllUser")
input.allUserChkBox(type="checkbox", id="chkSelectAll")
template(name="domainGeneral")
.domain-controls
input.js-domain-search(type="text" placeholder="{{_ 'search'}}" aria-label="{{_ 'search'}}")
button.js-domain-search-button(type="button") {{_ 'search'}}
.domain-pagination
button.js-domain-prev-page(type="button" class="{{#unless hasPrevPage}}disabled{{/unless}}" aria-label="{{_ 'previous'}}") {{_ 'previous'}}
span.domain-page-info {{currentPage}} / {{totalPages}}
button.js-domain-next-page(type="button" class="{{#unless hasNextPage}}disabled{{/unless}}" aria-label="{{_ 'next'}}") {{_ 'next'}}
table
thead
tr
th {{_ 'domain'}}
th {{_ 'domain-user-count'}}
th.js-domain-sort(scope="col" data-sort="domain") {{_ 'domain'}} {{domainSortIndicator 'domain'}}
th.js-domain-sort(scope="col" data-sort="count") {{_ 'domain-user-count'}} {{domainSortIndicator 'count'}}
tbody
if domainList.length
each domainList
+99 -11
View File
@@ -14,6 +14,7 @@ import InviteToBoardRolesSettings, {
const orgsPerPage = 25;
const teamsPerPage = 25;
const usersPerPage = 25;
const domainsPerPage = 25;
let userOrgsTeamsAction = ""; //poosible actions 'addOrg', 'addTeam', 'removeOrg' or 'removeTeam' when adding or modifying a user
let selectedUserChkBoxUserIds = [];
@@ -28,9 +29,9 @@ Template.people.onCreated(function () {
this.lockedUsersSetting = new ReactiveVar(false);
this.rolesSetting = new ReactiveVar(false);
this.templatesSetting = new ReactiveVar(false);
// #5850: Admin Panel > People > Domains tab.
// #5850: Admin Panel > People > Domains tab. The domains table itself
// (domainGeneral) now owns its data via getDomainsWithUserCountsPage.
this.domainSetting = new ReactiveVar(false);
this.domains = new ReactiveVar([]);
this.subscribe('inviteToBoardRolesSettings');
this.findOrgsOptions = new ReactiveVar({});
this.findTeamsOptions = new ReactiveVar({});
@@ -205,12 +206,9 @@ Template.people.onCreated(function () {
this.templatesSetting.set('templates-setting' === targetID);
this.domainSetting.set('domains-setting' === targetID);
// #5850: load the domains + per-domain user counts when the tab opens.
if ('domains-setting' === targetID) {
Meteor.call('getDomainsWithUserCounts', (err, res) => {
if (!err) this.domains.set(res || []);
});
}
// The Domains table (domainGeneral) now fetches its own single page from
// getDomainsWithUserCountsPage (server-side search / sort / pagination), so
// the parent no longer eagerly loads every domain into the browser.
// When switching to locked users tab, refresh the locked users list
if ('locked-users-setting' === targetID) {
@@ -292,9 +290,6 @@ Template.people.helpers({
domainSetting() {
return Template.instance().domainSetting;
},
domainList() {
return Template.instance().domains.get();
},
orgList() {
const tpl = Template.instance();
// The 'org' publication already returns only the current page (server-side
@@ -1897,3 +1892,96 @@ Template.settingsUserPopup.helpers({
return Template.instance().errorMessage.get();
},
});
// Admin Panel > People > Domains table. Self-contained (like the Board Table
// view): it keeps its own search / sort / page state and fetches only ONE page
// from the server method getDomainsWithUserCountsPage, so the whole domain list
// is never loaded into the browser.
Template.domainGeneral.onCreated(function () {
this.searchQuery = new ReactiveVar('');
this.sortField = new ReactiveVar('domain'); // domain | count
this.sortDirection = new ReactiveVar(1); // 1 ascending, -1 descending
this.page = new ReactiveVar(1);
this.pageData = new ReactiveVar({ rows: [], total: 0, totalPages: 1 });
this.autorun(() => {
const params = {
search: this.searchQuery.get(),
sortField: this.sortField.get(),
sortDirection: this.sortDirection.get(),
page: this.page.get(),
perPage: domainsPerPage,
};
Meteor.call('getDomainsWithUserCountsPage', params, (err, res) => {
if (!err && res) {
this.pageData.set(res);
// Server clamps the page into range; mirror that so the controls agree.
if (typeof res.page === 'number' && res.page !== this.page.get()) {
this.page.set(res.page);
}
}
});
});
});
Template.domainGeneral.helpers({
domainList() {
return Template.instance().pageData.get().rows;
},
currentPage() {
return Template.instance().page.get();
},
totalPages() {
return Template.instance().pageData.get().totalPages || 1;
},
hasPrevPage() {
return Template.instance().page.get() > 1;
},
hasNextPage() {
const tpl = Template.instance();
return tpl.page.get() < (tpl.pageData.get().totalPages || 1);
},
// Excel-like sort arrow on the active column, matching the Board Table view.
domainSortIndicator(field) {
const tpl = Template.instance();
if (tpl.sortField.get() !== field) return '';
return tpl.sortDirection.get() === 1 ? '▲' : '▼';
},
});
Template.domainGeneral.events({
'click .js-domain-search-button'(event, tpl) {
event.preventDefault();
tpl.searchQuery.set(tpl.$('.js-domain-search').val() || '');
tpl.page.set(1);
},
'keydown .js-domain-search'(event, tpl) {
if (event.keyCode === 13) {
event.preventDefault();
tpl.searchQuery.set(tpl.$('.js-domain-search').val() || '');
tpl.page.set(1);
}
},
'click .js-domain-prev-page'(event, tpl) {
event.preventDefault();
const current = tpl.page.get();
if (current > 1) tpl.page.set(current - 1);
},
'click .js-domain-next-page'(event, tpl) {
event.preventDefault();
const current = tpl.page.get();
if (current < (tpl.pageData.get().totalPages || 1)) tpl.page.set(current + 1);
},
'click .js-domain-sort'(event, tpl) {
event.preventDefault();
const field = event.currentTarget.dataset.sort;
if (!field) return;
if (tpl.sortField.get() === field) {
tpl.sortDirection.set(tpl.sortDirection.get() * -1);
} else {
tpl.sortField.set(field);
tpl.sortDirection.set(1);
}
tpl.page.set(1);
},
});
+9 -4
View File
@@ -55,9 +55,14 @@ template(name='homeSidebar')
i.fa.fa-comment-o
| {{_ 'activities'}}
a.flex.js-toggle-show-activities(title="{{_ 'show-activities'}}")
i.fa(class="{{#if showActivities}}fa-check{{else}}fa-square-o{{/if}}")
span {{_ 'show-activities'}}
if showActivities
a.flex.activities-eye-toggle.js-toggle-show-activities(title="{{_ 'hide-activities'}}" aria-label="{{_ 'hide-activities'}}")
i.fa.fa-eye.eye-icon
span {{_ 'hide-activities'}}
else
a.flex.activities-eye-toggle.js-toggle-show-activities(title="{{_ 'show-activities'}}" aria-label="{{_ 'show-activities'}}")
i.fa.fa-eye-slash.eye-slash-icon
span {{_ 'show-activities'}}
+activities(mode="board")
template(name="membersWidget")
@@ -823,7 +828,7 @@ template(name="labelsWidget")
| {{_ 'labels'}}
.board-widget-content
each currentBoard.labels
a.card-label(class="card-label-{{color}}"
a.card-label(class="{{labelColorClass color}}" style="{{labelColorStyle color}}"
class="{{#if currentUser.isNotCommentOnly}}{{#if currentUser.isNotWorker}}js-label{{/if}}{{/if}}")
span.card-label-name
+viewer
@@ -29,7 +29,7 @@ template(name="filterSidebar")
each currentBoard.labels
li
a.name.js-toggle-label-filter(data-filter-id="{{_id}}")
span.card-label.square(class="card-label-{{color}}")
span.card-label.square(class="{{labelColorClass color}}" style="{{labelColorStyle color}}")
span.sidebar-list-item-description
if name
= name
@@ -188,7 +188,7 @@ template(name="multiselectionSidebar")
each currentBoard.labels
li
a.name.js-toggle-label-multiselection
span.card-label.square(class="card-label-{{color}}")
span.card-label.square(class="{{labelColorClass color}}" style="{{labelColorStyle color}}")
span.sidebar-list-item-description
if name
= name
@@ -1,5 +1,5 @@
template(name="swimlaneHeader")
.swimlane-header-wrap.js-swimlane-header(class=colorClass title="{{_ 'rename'}}")
.swimlane-header-wrap.js-swimlane-header(class=colorClass style=colorStyle title="{{_ 'rename'}}")
if this.isTemplateContainer
+swimlaneFixedHeader(this)
else
@@ -120,6 +120,10 @@ template(name="setSwimlaneColorPopup")
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
if(isSelected color)
i.fa.fa-check
// #5514: native color wheel for picking a custom RGB / hex color
.flush-left.color-wheel-wrap
label(for="swimlaneColorWheel") {{_ 'custom-color'}}
input.js-swimlane-color-wheel#swimlaneColorWheel(type="color" value=currentColorHex title="{{_ 'custom-color'}}")
// Buttons aligned left too
.flush-left
button.primary.confirm.js-submit(style="margin-inline-start:0") {{_ 'save'}}
@@ -1,6 +1,7 @@
import { TAPi18n } from '/imports/i18n';
import { ReactiveCache } from '/imports/reactiveCache';
import { SWIMLANE_COLORS } from '/models/metadata/colors';
import { isHexColor, toHex } from '/models/lib/contrastColor';
import Swimlanes from '/models/swimlanes';
import { Utils } from '/client/lib/utils';
const { calculateIndexData } = Utils;
@@ -166,6 +167,10 @@ Template.setSwimlaneColorPopup.helpers({
isSelected(color) {
return Template.instance().currentColor.get() === color;
},
// #5514: current color as a '#rrggbb' hex for the native color wheel <input>.
currentColorHex() {
return toHex(Template.instance().currentColor.get()) || '#0079bf';
},
});
Template.setSwimlaneColorPopup.events({
@@ -178,6 +183,13 @@ Template.setSwimlaneColorPopup.events({
const paletteData = Blaze.getData(event.currentTarget);
tpl.currentColor.set(paletteData?.color);
},
// #5514: picking from the native color wheel stores a custom hex.
'input .js-swimlane-color-wheel'(event, tpl) {
const value = event.currentTarget.value;
if (isHexColor(value)) {
tpl.currentColor.set(value);
}
},
async 'click .js-submit'(event, tpl) {
event.preventDefault();
await tpl.currentSwimlane.setColor(tpl.currentColor.get());
+13
View File
@@ -98,6 +98,19 @@ body.mobile-mode .auth-layout .auth-dialog .at-form .password-input-container .p
margin-top: 2vh;
color: #4d4d4d;
}
/* #4394 (security): when registration / forgot-password are disabled in the
Admin Panel, keep the corresponding links hidden even after useraccounts
re-renders the form on a failed login. The class lives on the stable <body>
ancestor (set in layouts.js), so this rule re-hides every recreated copy of
the link — unlike a one-shot inline display:none that the re-render dropped. */
body.registration-disabled .at-signup-link,
body.registration-disabled .at-signUp {
display: none !important;
}
body.forgotpwd-disabled .at-pwd-link,
body.forgotpwd-disabled .at-forgotPwd {
display: none !important;
}
.auth-layout .auth-dialog .at-form .at-signup-link .at-signUp,
.auth-layout .auth-dialog .at-form .at-signin-link .at-signUp,
.auth-layout .auth-dialog .at-form .at-forgotPwd .at-signUp,
+21
View File
@@ -29,6 +29,27 @@ import {
calendar,
} from '/imports/lib/dateUtils';
import { Utils } from '/client/lib/utils';
import { isHexColor, contrastText } from '/models/lib/contrastColor';
// #5514: a color (label / list / swimlane / card) may be either a named palette
// color rendered via a CSS class (e.g. `card-label-green`) or a custom
// '#rrggbb' hex chosen from the color wheel. For a hex value there is no CSS
// class, so we emit an inline `background-color` plus an automatically readable
// text `color` (contrastText). These helpers let templates keep the class path
// for named colors and switch to inline styles for hex.
// Class for a label chip: `card-label-<name>` for named colors, empty for hex.
Blaze.registerHelper('labelColorClass', color =>
isHexColor(color) ? '' : `card-label-${color}`,
);
// Inline style for a label chip: background + readable text for a hex color,
// empty for a named color (its CSS class already sets both).
Blaze.registerHelper('labelColorStyle', color =>
isHexColor(color)
? `background-color:${color};color:${contrastText(color)};`
: '',
);
Blaze.registerHelper('currentBoard', () => {
const ret = Utils.getCurrentBoard();
+19 -29
View File
@@ -19,8 +19,9 @@ import {
now,
createDate,
fromNow,
calendar
calendar
} from '/imports/lib/dateUtils';
import { weekRange } from '/models/lib/weekStart';
// Sidebar is imported late to avoid circular dependency (sidebar.js needs its
// jade template loaded first, but router.js → filter.js would load it too early)
let _Sidebar;
@@ -119,44 +120,33 @@ class DateFilter {
// weeks up to today +/- offset. This considers the user's preferred
// start of week day (as defined by Meteor).
relativeWeek(offset, week) {
if (this._filterState == 'thisweek') {
// #4881: toggle per-week so clicking the same button again clears it, but
// clicking the OTHER week switches to it instead of just resetting (the old
// code reset on either state, so you could not go straight from "this week"
// to "next week").
const targetState = week === 'next' ? 'nextweek' : 'thisweek';
if (this._filterState === targetState) {
this.reset();
return;
}
if (this._filterState == 'nextweek') {
this.reset();
return;
}
// getStartDayOfWeek returns the offset from Sunday of the user's
// preferred starting day of the week. This date should be added
// to the moment start of week to get the real start of week date.
// The default is 1, meaning Monday.
// #4881: the old window came from startOf(now(), 'week'), but native
// dateUtils.startOf() has no 'week' case, so it returned "now" unchanged and
// the window started at today + startDayOfWeek — i.e. it selected NEXT
// week's cards for "this week" and ignored the configured start weekday.
// weekRange() computes the correct window that CONTAINS today for the user's
// configured start day of week (0=Sunday..6=Saturday, default Monday).
const currentUser = ReactiveCache.getCurrentUser();
const weekStartDay = currentUser ? currentUser.getStartDayOfWeek() : 1;
const weekOffset = week === 'next' ? 1 : 0;
const { start: WeekStart, end: WeekEnd } = weekRange(now(), weekStartDay, weekOffset);
if (week === 'this') {
// Create week start and end dates
var WeekStart = startOf(add(startOf(now(), 'week'), weekStartDay, 'days'), 'day');
var WeekEnd = endOf(add(WeekStart, 6, 'days'), 'day');
this._updateState('thisweek');
} else if (week === 'next') {
// Create next week start and end dates
var WeekStart = startOf(add(startOf(now(), 'week'), weekStartDay + 7, 'days'), 'day');
var WeekEnd = endOf(add(WeekStart, 6, 'days'), 'day');
this._updateState('nextweek');
}
var startDate = WeekStart;
var endDate = WeekEnd;
this._updateState(targetState);
if (offset >= 0) {
this._filter = { $gte: startDate, $lte: endDate };
this._filter = { $gte: WeekStart, $lte: WeekEnd };
} else {
this._filter = { $lte: startDate, $gte: endDate };
this._filter = { $lte: WeekStart, $gte: WeekEnd };
}
}
+27 -101
View File
@@ -4,6 +4,7 @@ import { Tracker } from 'meteor/tracker';
import { TAPi18n } from '/imports/i18n';
import { EscapeActions } from '/client/lib/escapeActions';
import { Utils } from '/client/lib/utils';
import { computePopupOffset } from '/client/lib/popupOffset';
window.Popup = new (class {
constructor() {
@@ -222,108 +223,33 @@ window.Popup = new (class {
return () => {
Utils.windowResizeDep.depend();
if (Utils.isMiniScreen()) return { left: 0, top: 0 };
// #5667: read the current page scroll and the opener's document offset,
// then delegate the geometry to the pure, unit-tested computePopupOffset.
// It lays the popup out in VIEWPORT coordinates — so a date-picker opened
// low on a scrolled page stays fully visible instead of extending past the
// visible area — and returns document coordinates for the absolute style.
const hasOpener = !!($element && $element.length);
const offset = hasOpener ? $element.offset() : null;
const opener = hasOpener
? { top: offset.top, left: offset.left, height: $element.outerHeight() }
: null;
const viewportWidth = $(window).width();
const viewportHeight = $(window).height();
const viewportPadding = 10;
// Calculate actual popup width based on CSS: min(380px, 55vw)
const popupWidth = Math.min(380, viewportWidth * 0.55);
// Card details popup: dock it to the top of the viewport so it overlays
// the global and board header bars (its z-index already sits above them)
// instead of opening downward from the clicked minicard.
if (popupName === 'cardDetailsPopup') {
const cardWidth = Math.min(600, viewportWidth * 0.8);
const centeredLeft = (viewportWidth - cardWidth) / 2;
// top is forced to 0 in CSS (.pop-over[data-popup="cardDetailsPopup"])
// so the card overlays the header bars; use the full viewport height.
return {
left: Math.max(viewportPadding, centeredLeft),
top: 0,
maxHeight: viewportHeight,
};
}
// If the opener element is missing (e.g., programmatic open), fallback to viewport origin
if (!$element || $element.length === 0) {
return {
left: viewportPadding,
top: viewportPadding,
maxHeight: viewportHeight - viewportPadding * 2,
};
}
const offset = $element.offset();
const openerTop = offset.top;
const openerBottom = offset.top + $element.outerHeight();
const clampedLeft = Math.max(
viewportPadding,
Math.min(offset.left, viewportWidth - popupWidth - viewportPadding),
);
// Check if this is an admin panel edit popup
const isAdminEditPopup = $element.hasClass('edit-user') ||
$element.hasClass('edit-org') ||
$element.hasClass('edit-team');
if (isAdminEditPopup) {
// Center the popup horizontally and use full height
const centeredLeft = (viewportWidth - popupWidth) / 2;
return {
left: Math.max(viewportPadding, centeredLeft), // Ensure popup doesn't go off screen
top: viewportPadding, // Start from top with small margin
maxHeight: viewportHeight - viewportPadding * 2, // Use full height minus small margins
};
}
// Calculate available heights around the opener
const spaceBelow = viewportHeight - openerBottom - viewportPadding;
const spaceAbove = openerTop - viewportPadding;
const preferBelow = spaceBelow >= spaceAbove;
// For language popup, don't use dynamic height to avoid overlapping board
const isLanguagePopup = $element.hasClass('js-change-language');
let availableHeight;
if (isLanguagePopup) {
// For language popup, position content area below right vertical scrollbar
const languageTop = openerBottom;
const languageAvailable = Math.max(
0,
viewportHeight - languageTop - viewportPadding,
);
const calculatedHeight = Math.min(
languageAvailable,
viewportHeight * 0.5,
); // Max 50% of viewport
return {
left: clampedLeft,
top: languageTop,
maxHeight: Math.max(calculatedHeight, 0),
};
} else {
// For other popups, choose the side with more space and keep popup fully in viewport.
if (preferBelow) {
availableHeight = Math.max(0, Math.min(spaceBelow, viewportHeight * 0.8));
return {
left: clampedLeft,
top: openerBottom,
maxHeight: availableHeight,
};
}
availableHeight = Math.max(0, Math.min(spaceAbove, viewportHeight * 0.8));
const top = Math.max(viewportPadding, openerTop - availableHeight);
return {
left: clampedLeft,
top,
maxHeight: availableHeight,
};
}
return computePopupOffset({
viewportWidth: $(window).width(),
viewportHeight: $(window).height(),
scrollTop: $(window).scrollTop() || 0,
scrollLeft: $(window).scrollLeft() || 0,
opener,
popupName,
isMiniScreen: Utils.isMiniScreen(),
isAdminEditPopup:
hasOpener &&
($element.hasClass('edit-user') ||
$element.hasClass('edit-org') ||
$element.hasClass('edit-team')),
isLanguagePopup: hasOpener && $element.hasClass('js-change-language'),
viewportPadding: 10,
});
};
}
+118
View File
@@ -0,0 +1,118 @@
'use strict';
// Pure geometry for Popup._getOffset — extracted so the positioning math is
// unit-testable without a DOM / Meteor (see tests/popupOffset.test.cjs).
//
// #5667 ("Problem when scrolling in a map with date fields"): a date-picker
// calendar (due/start/end date, or a date custom field) opened low on the screen
// appeared partly outside the visible area, and — because the pop-over is
// `position: absolute` (document coordinates) — trying to scroll it into view
// moved it along with the page, so the calendar could never be seen fully.
//
// Root cause: _getOffset computed the space above / below the opener (and the
// clamped `top`) from the opener's DOCUMENT offset (`$el.offset()`) mixed with
// the VIEWPORT height, ignoring the page scroll. On a scrolled page that placed
// the anchored popup outside the visible viewport.
//
// Fix: do the space / clamp math in VIEWPORT coordinates (subtract
// scrollTop/scrollLeft), then convert the chosen top/left back to DOCUMENT
// coordinates (add the scroll back) for the absolute style. The popup box is then
// always laid out fully within the visible viewport. When the page is not
// scrolled (scrollTop === scrollLeft === 0) the output is identical to the
// previous behaviour, so nothing regresses in the common case.
function computePopupOffset(params) {
const {
viewportWidth,
viewportHeight,
scrollTop = 0,
scrollLeft = 0,
// Opener document offset { top, left, height }, or null for a programmatic
// open with no reference element.
opener = null,
popupName,
isMiniScreen = false,
isAdminEditPopup = false,
isLanguagePopup = false,
viewportPadding = 10,
} = params;
if (isMiniScreen) return { left: 0, top: 0 };
// Actual popup width from CSS: min(380px, 55vw).
const popupWidth = Math.min(380, viewportWidth * 0.55);
// Card details popup: docked to the top of the viewport (CSS also forces
// top:0) so it overlays the header bars instead of opening from the minicard.
if (popupName === 'cardDetailsPopup') {
const cardWidth = Math.min(600, viewportWidth * 0.8);
const centeredLeft = (viewportWidth - cardWidth) / 2;
return {
left: Math.max(viewportPadding, centeredLeft),
top: scrollTop, // viewport top in document coords
maxHeight: viewportHeight,
};
}
// No opener element: fall back to the top-left of the VISIBLE viewport.
if (!opener) {
return {
left: viewportPadding + scrollLeft,
top: viewportPadding + scrollTop,
maxHeight: viewportHeight - viewportPadding * 2,
};
}
// Opener position in viewport coordinates (this is the #5667 fix: the previous
// code used the raw document offset here).
const openerTopVp = opener.top - scrollTop;
const openerBottomVp = openerTopVp + opener.height;
const openerLeftVp = opener.left - scrollLeft;
const clampedLeftVp = Math.max(
viewportPadding,
Math.min(openerLeftVp, viewportWidth - popupWidth - viewportPadding),
);
const clampedLeft = clampedLeftVp + scrollLeft;
// Admin panel edit popups: horizontally centered, anchored to the viewport top.
if (isAdminEditPopup) {
const centeredLeft = (viewportWidth - popupWidth) / 2;
return {
left: Math.max(viewportPadding, centeredLeft),
top: viewportPadding + scrollTop,
maxHeight: viewportHeight - viewportPadding * 2,
};
}
const spaceBelow = viewportHeight - openerBottomVp - viewportPadding;
const spaceAbove = openerTopVp - viewportPadding;
const preferBelow = spaceBelow >= spaceAbove;
// Language popup: fixed-ish height below the opener, capped at 50% viewport.
if (isLanguagePopup) {
const languageTopVp = openerBottomVp;
const languageAvailable = Math.max(
0,
viewportHeight - languageTopVp - viewportPadding,
);
const calculatedHeight = Math.min(languageAvailable, viewportHeight * 0.5);
return {
left: clampedLeft,
top: languageTopVp + scrollTop,
maxHeight: Math.max(calculatedHeight, 0),
};
}
// Other popups: open on the side with more room and stay fully in the viewport.
if (preferBelow) {
const maxHeight = Math.max(0, Math.min(spaceBelow, viewportHeight * 0.8));
return { left: clampedLeft, top: openerBottomVp + scrollTop, maxHeight };
}
const maxHeight = Math.max(0, Math.min(spaceAbove, viewportHeight * 0.8));
const topVp = Math.max(viewportPadding, openerTopVp - maxHeight);
return { left: clampedLeft, top: topVp + scrollTop, maxHeight };
}
module.exports = { computePopupOffset };
+16 -6
View File
@@ -4,16 +4,26 @@ import { Tracker } from 'meteor/tracker';
import { findWhere, where, uniqBy, groupBy, indexBy, debounce, once } from '/imports/lib/collectionHelpers';
import Settings from '/models/settings';
import Users from '/models/users';
import { computeBoardBackground } from '/models/lib/boardBackground';
export const Utils = {
async setBackgroundImage(url) {
const currentBoard = Utils.getCurrentBoard();
if (currentBoard.backgroundImageURL !== undefined) {
$(".board-wrapper").css({"background":"url(" + currentBoard.backgroundImageURL + ")","background-size":"cover"});
$(".swimlane,.swimlane .list,.swimlane .list .list-body,.swimlane .list:first-child .list-body").css({"background-color":"transparent"});
$(".minicard").css({"opacity": "0.9"});
} else if (currentBoard["background-color"]) {
await currentBoard.setColor(currentBoard["background-color"]);
const bg = computeBoardBackground(currentBoard);
const swimlaneSelector =
".swimlane,.swimlane .list,.swimlane .list .list-body,.swimlane .list:first-child .list-body";
if (bg.type === "image") {
$(".board-wrapper").css({ "background": "url(" + bg.url + ")", "background-size": "cover" });
$(swimlaneSelector).css({ "background-color": "transparent" });
$(".minicard").css({ "opacity": "0.9" });
} else {
// #4978: clear any inline background left over from a previously shown
// board, so switching image -> color or image -> plain (e.g. via the
// favorites bar) actually removes the old image. The board's color, when
// any, is applied reactively via the `.board-wrapper` colorClass.
$(".board-wrapper").css({ "background": "", "background-size": "" });
$(swimlaneSelector).css({ "background-color": "" });
$(".minicard").css({ "opacity": "" });
}
},
/** returns the current board id
+2 -2
View File
@@ -10,7 +10,7 @@ This is without container (without Docker or Snap).
Right click and download files 1-4:
1. [wekan-9.78-win64.zip](https://github.com/wekan/wekan/releases/download/v9.78/wekan-9.78-win64.zip) or newest available at https://github.com/wekan/wekan/releases/
1. [wekan-9.83-win64.zip](https://github.com/wekan/wekan/releases/download/v9.83/wekan-9.83-win64.zip) or newest available at https://github.com/wekan/wekan/releases/
2. [node.exe](https://nodejs.org/dist/latest-v24.x/win-x64/node.exe)
@@ -22,7 +22,7 @@ Right click and download files 1-4:
6. Double click `mongodb-windows-x86_64-7.0.34-signed.msi` . In installer, uncheck downloading MongoDB compass.
7. Unzip `wekan-9.78-win64.zip` , inside it is directory `bundle`, to it copy other files:
7. Unzip `wekan-9.83-win64.zip` , inside it is directory `bundle`, to it copy other files:
```
bundle (directory)
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Menerima",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Cipta ruangan",
"createCustomFieldPopup-title": "Cipta ruangan",
"current": "sekarang",
"custom-color": "Custom color",
"custom-field-delete-pop": "Tidak boleh undur semula. Ianya akan menghapuskan ruangan khas daripada semua kad dan padamkan sejarahnya.",
"custom-field-checkbox": "kotak semak",
"custom-field-currency": "Matawang",
@@ -582,6 +584,7 @@
"fullname": "Nama Lengkap",
"header-logo-title": "Kembali ke laman panel anda",
"show-activities": "Tunjukkan Aktiviti",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Buat Panel",
"home": "Beranda",
"import": "Impor",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Picu",
"r-action": "Tindakan",
"r-when-a-card": "Ketika kartu",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aanvaar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Skep veld",
"createCustomFieldPopup-title": "Skep veld",
"current": "huidige",
"custom-color": "Custom color",
"custom-field-delete-pop": "Daar is geen ongedaan maak nie. Dit sal hierdie pasgemaakte veld van alle kaarte verwyder en sy geskiedenis vernietig.",
"custom-field-checkbox": "Merkblokkie",
"custom-field-currency": "Geldeenheid",
@@ -582,6 +584,7 @@
"fullname": "Volle Naam",
"header-logo-title": "Gaan terug na jou bordbladsy.",
"show-activities": "Wys aktiwiteite",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Skep bord",
"home": "Tuis",
"import": "Invoer",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Sneller",
"r-action": "Aksie",
"r-when-a-card": "Wanneer 'n kaart",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aanvaar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Skep veld",
"createCustomFieldPopup-title": "Skep veld",
"current": "huidige",
"custom-color": "Custom color",
"custom-field-delete-pop": "Daar is geen ongedaan maak nie. Dit sal hierdie pasgemaakte veld van alle kaarte verwyder en sy geskiedenis vernietig.",
"custom-field-checkbox": "Merkblokkie",
"custom-field-currency": "Geldeenheid",
@@ -582,6 +584,7 @@
"fullname": "Volle Naam",
"header-logo-title": "Gaan terug na jou bordbladsy.",
"show-activities": "Wys aktiwiteite",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Skep bord",
"home": "Tuis",
"import": "Invoer",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Sneller",
"r-action": "Aksie",
"r-when-a-card": "Wanneer 'n kaart",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "قبول",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "انشاء حقل",
"createCustomFieldPopup-title": "انشاء حقل",
"current": "الحالي",
"custom-color": "Custom color",
"custom-field-delete-pop": "این اقدام فیلد سفارشی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
"custom-field-checkbox": "جعبه انتخابی",
"custom-field-currency": "عملة",
@@ -582,6 +584,7 @@
"fullname": "الإسم الكامل",
"header-logo-title": "الرجوع إلى صفحة اللوحات",
"show-activities": "عرض الأنشطة",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
"home": "الرئيسية",
"import": "وارد کردن",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "تریگر",
"r-action": "عملیات",
"r-when-a-card": "زمانی که کارت",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "قبول",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "انشاء حقل",
"createCustomFieldPopup-title": "انشاء حقل",
"current": "الحالي",
"custom-color": "Custom color",
"custom-field-delete-pop": "این اقدام فیلد سفارشی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
"custom-field-checkbox": "جعبه انتخابی",
"custom-field-currency": "عملة",
@@ -582,6 +584,7 @@
"fullname": "الإسم الكامل",
"header-logo-title": "الرجوع إلى صفحة اللوحات",
"show-activities": "عرض الأنشطة",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
"home": "الرئيسية",
"import": "وارد کردن",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "تریگر",
"r-action": "عملیات",
"r-when-a-card": "زمانی که کارت",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "قبول",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "انشاء حقل",
"createCustomFieldPopup-title": "انشاء حقل",
"current": "الحالي",
"custom-color": "Custom color",
"custom-field-delete-pop": "این اقدام فیلد سفارشی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
"custom-field-checkbox": "جعبه انتخابی",
"custom-field-currency": "عملة",
@@ -582,6 +584,7 @@
"fullname": "الإسم الكامل",
"header-logo-title": "الرجوع إلى صفحة اللوحات",
"show-activities": "عرض الأنشطة",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
"home": "الرئيسية",
"import": "وارد کردن",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "تریگر",
"r-action": "عملیات",
"r-when-a-card": "زمانی که کارت",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "قبول",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "انشاء حقل",
"createCustomFieldPopup-title": "انشاء حقل",
"current": "الحالي",
"custom-color": "Custom color",
"custom-field-delete-pop": "این اقدام فیلد سفارشی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
"custom-field-checkbox": "جعبه انتخابی",
"custom-field-currency": "عملة",
@@ -582,6 +584,7 @@
"fullname": "الإسم الكامل",
"header-logo-title": "الرجوع إلى صفحة اللوحات",
"show-activities": "عرض الأنشطة",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
"home": "الرئيسية",
"import": "وارد کردن",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "تریگر",
"r-action": "عملیات",
"r-when-a-card": "زمانی که کارت",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Qəbul edin",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Sahə yaradın",
"createCustomFieldPopup-title": "Sahə yaradın",
"current": "cari",
"custom-color": "Custom color",
"custom-field-delete-pop": "Geri qaytarma yoxdur. Bu, bu fərdi sahəni bütün kartlardan siləcək və onun tarixçəsini məhv edəcək.",
"custom-field-checkbox": "Yoxlama qutusu",
"custom-field-currency": "Valyuta",
@@ -582,6 +584,7 @@
"fullname": "Tam adı",
"header-logo-title": "Lövhələr səhifəsinə qayıdın.",
"show-activities": "Fəaliyyətləri göstərin",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Şura yaradın",
"home": "Ev",
"import": "İdxal",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Tətik",
"r-action": "Fəaliyyət",
"r-when-a-card": "Bir kart olanda",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Qəbul edin",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Sahə yaradın",
"createCustomFieldPopup-title": "Sahə yaradın",
"current": "cari",
"custom-color": "Custom color",
"custom-field-delete-pop": "Geri qaytarma yoxdur. Bu, bu fərdi sahəni bütün kartlardan siləcək və onun tarixçəsini məhv edəcək.",
"custom-field-checkbox": "Yoxlama qutusu",
"custom-field-currency": "Valyuta",
@@ -582,6 +584,7 @@
"fullname": "Tam adı",
"header-logo-title": "Lövhələr səhifəsinə qayıdın.",
"show-activities": "Fəaliyyətləri göstərin",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Şura yaradın",
"home": "Ev",
"import": "İdxal",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Tətik",
"r-action": "Fəaliyyət",
"r-when-a-card": "Bir kart olanda",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Qəbul edin",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Sahə yaradın",
"createCustomFieldPopup-title": "Sahə yaradın",
"current": "cari",
"custom-color": "Custom color",
"custom-field-delete-pop": "Geri qaytarma yoxdur. Bu, bu fərdi sahəni bütün kartlardan siləcək və onun tarixçəsini məhv edəcək.",
"custom-field-checkbox": "Yoxlama qutusu",
"custom-field-currency": "Valyuta",
@@ -582,6 +584,7 @@
"fullname": "Tam adı",
"header-logo-title": "Lövhələr səhifəsinə qayıdın.",
"show-activities": "Fəaliyyətləri göstərin",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Şura yaradın",
"home": "Ev",
"import": "İdxal",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Tətik",
"r-action": "Fəaliyyət",
"r-when-a-card": "Bir kart olanda",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Приемам",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Създай Поле",
"createCustomFieldPopup-title": "Създай Поле",
"current": "сегашен",
"custom-color": "Custom color",
"custom-field-delete-pop": "Опозив ове радње неће бити могућ. Радњом се уклања ова придружена рубрика из свих предмета и уништива њена претходна историја употребе.",
"custom-field-checkbox": "Чекбокс",
"custom-field-currency": "Валута",
@@ -582,6 +584,7 @@
"fullname": "Име",
"header-logo-title": "Назад към страницата с Вашите табла.",
"show-activities": "Писани записник",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Създай Табло",
"home": "Начало",
"import": "Импорт",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Добави спусък",
"r-action": "Действие",
"r-when-a-card": "Когато карта",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Asantiñ",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Créer un champ personnalisé",
"createCustomFieldPopup-title": "Créer un champ personnalisé",
"current": "actuel",
"custom-color": "Custom color",
"custom-field-delete-pop": "Cette action est irréversible. Elle supprimera ce champ personnalisé de toutes les cartes et détruira son historique.",
"custom-field-checkbox": "Case à cocher",
"custom-field-currency": "Devise",
@@ -582,6 +584,7 @@
"fullname": "Nom complet",
"header-logo-title": "Retourner à la page des tableaux",
"show-activities": "Afficher les activités",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Créer un tableau",
"home": "Accueil",
"import": "Importer",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Déclencheur",
"r-action": "Action",
"r-when-a-card": "Quand une carte",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accepta",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear campament",
"createCustomFieldPopup-title": "Crear campament",
"current": "Real",
"custom-color": "Custom color",
"custom-field-delete-pop": "No hi ha cap desfer. Això eliminarà aquest camp personalitzat de totes les cartes i destruirà el seu historial.",
"custom-field-checkbox": "casella de selecció",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nom complet",
"header-logo-title": "Torna a la teva pàgina de taulers",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crea tauler",
"home": "Inici",
"import": "importa",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Disparador",
"r-action": "Acció",
"r-when-a-card": "Quan una fitxa",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Acceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear campament",
"createCustomFieldPopup-title": "Crear campament",
"current": "Real",
"custom-color": "Custom color",
"custom-field-delete-pop": "No hi ha cap desfer. Això eliminarà aquest camp personalitzat de totes les cartes i destruirà el seu historial.",
"custom-field-checkbox": "casella de selecció",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nom complet",
"header-logo-title": "Torna a la teva pàgina de taulers",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crea tauler",
"home": "Inici",
"import": "importa",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Disparador",
"r-action": "Acció",
"r-when-a-card": "Quan una fitxa",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accepta",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear campament",
"createCustomFieldPopup-title": "Crear campament",
"current": "Real",
"custom-color": "Custom color",
"custom-field-delete-pop": "No hi ha cap desfer. Això eliminarà aquest camp personalitzat de totes les cartes i destruirà el seu historial.",
"custom-field-checkbox": "casella de selecció",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nom complet",
"header-logo-title": "Torna a la teva pàgina de taulers",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crea tauler",
"home": "Inici",
"import": "importa",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Disparador",
"r-action": "Acció",
"r-when-a-card": "Quan una fitxa",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "接受",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "创建字段",
"createCustomFieldPopup-title": "创建字段",
"current": "当前的",
"custom-color": "Custom color",
"custom-field-delete-pop": "无法撤消。这将从所有卡中删除此自定义字段并销毁其历史记录。",
"custom-field-checkbox": "复选框",
"custom-field-currency": "货币",
@@ -582,6 +584,7 @@
"fullname": "姓名",
"header-logo-title": "返回您的图板页面。",
"show-activities": "展会活动",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "创建板",
"home": "家",
"import": "进口",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "扳机",
"r-action": "行动",
"r-when-a-card": "当一张卡",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Přijmout",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Vytvořit pole",
"createCustomFieldPopup-title": "Vytvořit pole",
"current": "Aktuální",
"custom-color": "Custom color",
"custom-field-delete-pop": "Nelze vrátit zpět. Toto odebere toto vlastní pole ze všech karet a zničí jeho historii.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Měna",
@@ -582,6 +584,7 @@
"fullname": "Celé jméno",
"header-logo-title": "Jit zpět na stránku s tably.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Vytvořit tablo",
"home": "Domů",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Spouštěč",
"r-action": "Akce",
"r-when-a-card": "Pokud karta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Přijmout",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Vytvořit pole",
"createCustomFieldPopup-title": "Vytvořit pole",
"current": "Aktuální",
"custom-color": "Custom color",
"custom-field-delete-pop": "Nelze vrátit zpět. Toto odebere toto vlastní pole ze všech karet a zničí jeho historii.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Měna",
@@ -582,6 +584,7 @@
"fullname": "Celé jméno",
"header-logo-title": "Jit zpět na stránku s tably.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Vytvořit tablo",
"home": "Domů",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Spouštěč",
"r-action": "Akce",
"r-when-a-card": "Pokud karta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Derbyn",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Creu Maes",
"createCustomFieldPopup-title": "Creu Maes",
"current": "presennol",
"custom-color": "Custom color",
"custom-field-delete-pop": "Does dim dadwneud. Bydd hyn yn dileu'r maes arfer hwn o bob cerdyn ac yn dinistrio ei hanes.",
"custom-field-checkbox": "Blwch ticio",
"custom-field-currency": "Arian cyfred",
@@ -582,6 +584,7 @@
"fullname": "Enw Llawn",
"header-logo-title": "Ewch yn ôl i dudalen eich byrddau.",
"show-activities": "Gweithgareddau Sioe",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Creu Bwrdd",
"home": "Cartref",
"import": "Mewnforio",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Sbardun",
"r-action": "Gweithred",
"r-when-a-card": "Pan fydd cerdyn",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Derbyn",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Creu Maes",
"createCustomFieldPopup-title": "Creu Maes",
"current": "presennol",
"custom-color": "Custom color",
"custom-field-delete-pop": "Does dim dadwneud. Bydd hyn yn dileu'r maes arfer hwn o bob cerdyn ac yn dinistrio ei hanes.",
"custom-field-checkbox": "Blwch ticio",
"custom-field-currency": "Arian cyfred",
@@ -582,6 +584,7 @@
"fullname": "Enw Llawn",
"header-logo-title": "Ewch yn ôl i dudalen eich byrddau.",
"show-activities": "Gweithgareddau Sioe",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Creu Bwrdd",
"home": "Cartref",
"import": "Mewnforio",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Sbardun",
"r-action": "Gweithred",
"r-when-a-card": "Pan fydd cerdyn",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accepter",
"activity-changedTitle": "ændrede titel til %s af %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "slettede kortet __card__ fra listen __list__ i svømmebanen __swimlane__ på tavlen __board__",
"act-removeBoard": "slettede tavlen __board__",
"act-removeList": "slettede listen __list__ fra tavlen __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Opret felt",
"createCustomFieldPopup-title": "Opret felt",
"current": "nuværende",
"custom-color": "Custom color",
"custom-field-delete-pop": "Du kan ikke fortryde handlingen. Dette vil fjerne dette brugerdefinerede felt fra alle kort og tilintetgøre dens historik.",
"custom-field-checkbox": "Afkrydsningsfelt",
"custom-field-currency": "Valuta",
@@ -582,6 +584,7 @@
"fullname": "Fuldt navn",
"header-logo-title": "Gå tilbage til siden med dine tavler",
"show-activities": "Visa aktiviteter",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Opret tavle",
"home": "Hjem",
"import": "Importér",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Træk en trigger og en handling ind i byggeren, og tilføj derefter reglen. Træk en handling over på en eksisterende regel for at ændre, hvad den gør.",
"r-drop-trigger": "træk en udløser hertil",
"r-drop-action": "træk en handling hertil",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Eksporter regler til JSON",
"r-export-csv": "Eksporter regler til CSV",
"r-import-json": "Importer regler fra JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Markér kort som ikke fuldført",
"r-move-all-cards": "Flyt alle kort i en liste",
"r-set-date-relative": "Angiv dato i forhold til dags dato",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Udløser",
"r-action": "Handling",
"r-when-a-card": "Når et kort",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Akzeptieren",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Feld erstellen",
"createCustomFieldPopup-title": "Feld erstellen",
"current": "aktuell",
"custom-color": "Custom color",
"custom-field-delete-pop": "Dies wird das Feld aus allen Karten entfernen und den dazugehörigen Verlauf löschen. Die Aktion kann nicht rückgängig gemacht werden.",
"custom-field-checkbox": "Kontrollkästchen",
"custom-field-currency": "Währung",
@@ -582,6 +584,7 @@
"fullname": "Vollständiger Name",
"header-logo-title": "Zurück zur Board Seite.",
"show-activities": "Aktivitäten anzeigen",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Board erstellen",
"home": "Home",
"import": "Importieren",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Auslöser",
"r-action": "Aktion",
"r-when-a-card": "Wenn Karte",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Akzeptieren",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Feld erstellen",
"createCustomFieldPopup-title": "Feld erstellen",
"current": "aktuell",
"custom-color": "Custom color",
"custom-field-delete-pop": "Dies wird das Feld aus allen Karten entfernen und den dazugehörigen Verlauf löschen. Die Aktion kann nicht rückgängig gemacht werden.",
"custom-field-checkbox": "Kontrollkästchen",
"custom-field-currency": "Währung",
@@ -582,6 +584,7 @@
"fullname": "Vollständiger Name",
"header-logo-title": "Zurück zur Board Seite.",
"show-activities": "Aktivitäten anzeigen",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Board erstellen",
"home": "Home",
"import": "Importieren",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Auslöser",
"r-action": "Aktion",
"r-when-a-card": "Wenn Karte",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Akzeptieren",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Feld erstellen",
"createCustomFieldPopup-title": "Feld erstellen",
"current": "aktuell",
"custom-color": "Custom color",
"custom-field-delete-pop": "Dies wird das Feld aus allen Karten entfernen und den dazugehörigen Verlauf löschen. Die Aktion kann nicht rückgängig gemacht werden.",
"custom-field-checkbox": "Kontrollkästchen",
"custom-field-currency": "Währung",
@@ -582,6 +584,7 @@
"fullname": "Vollständiger Name",
"header-logo-title": "Zurück zur Board Seite.",
"show-activities": "Aktivitäten anzeigen",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Board erstellen",
"home": "Home",
"import": "Importieren",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Auslöser",
"r-action": "Aktion",
"r-when-a-card": "Wenn Karte",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Akzeptieren",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Feld erstellen",
"createCustomFieldPopup-title": "Feld erstellen",
"current": "aktuell",
"custom-color": "Custom color",
"custom-field-delete-pop": "Dies wird das Feld aus allen Karten entfernen und den dazugehörigen Verlauf löschen. Die Aktion kann nicht rückgängig gemacht werden.",
"custom-field-checkbox": "Kontrollkästchen",
"custom-field-currency": "Währung",
@@ -582,6 +584,7 @@
"fullname": "Vollständiger Name",
"header-logo-title": "Zurück zur Board Seite.",
"show-activities": "Aktivitäten anzeigen",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Board erstellen",
"home": "Home",
"import": "Importieren",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Auslöser",
"r-action": "Aktion",
"r-when-a-card": "Wenn Karte",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Αποδοχή",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Δημιουργία Πεδίου",
"createCustomFieldPopup-title": "Δημιουργία Πεδίου",
"current": "τρέχων",
"custom-color": "Custom color",
"custom-field-delete-pop": "Non potrai tornare indietro. Questa azione rimuoverà questo campo personalizzato da tutte le schede ed eliminerà ogni sua traccia.",
"custom-field-checkbox": "Casella di scelta",
"custom-field-currency": "Νόμισμα",
@@ -582,6 +584,7 @@
"fullname": "Πλήρες Όνομα",
"header-logo-title": "Επιστροφή στη σελίδα των πινάκων σας.",
"show-activities": "Mostra Attività",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Δημιουργία Πίνακα",
"home": "Αρχική",
"import": "Εισαγωγή",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Déclencheur",
"r-action": "Ενέργεια",
"r-when-a-card": "Όταν μία κάρτα",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Αποδοχή",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Δημιουργία Πεδίου",
"createCustomFieldPopup-title": "Δημιουργία Πεδίου",
"current": "τρέχων",
"custom-color": "Custom color",
"custom-field-delete-pop": "Non potrai tornare indietro. Questa azione rimuoverà questo campo personalizzato da tutte le schede ed eliminerà ogni sua traccia.",
"custom-field-checkbox": "Casella di scelta",
"custom-field-currency": "Νόμισμα",
@@ -582,6 +584,7 @@
"fullname": "Πλήρες Όνομα",
"header-logo-title": "Επιστροφή στη σελίδα των πινάκων σας.",
"show-activities": "Mostra Attività",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Δημιουργία Πίνακα",
"home": "Αρχική",
"import": "Εισαγωγή",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Déclencheur",
"r-action": "Ενέργεια",
"r-when-a-card": "Όταν μία κάρτα",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Accept",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"current": "current",
"custom-color": "Custom color",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
"custom-field-currency": "Currency",
@@ -582,6 +584,7 @@
"fullname": "Full Name",
"header-logo-title": "Go back to your boards page.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Create Board",
"home": "Home",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Action",
"r-when-a-card": "When a card",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Akcepti",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Plena nomo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Krei tavolon",
"home": "Hejmo",
"import": "Importi",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear Campo",
"createCustomFieldPopup-title": "Crear Campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre Completo",
"header-logo-title": "Retroceder a tu página de tableros.",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear Tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Divisa",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a su página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Desencadenador",
"r-action": "Acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aceptar",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Crear un campo",
"createCustomFieldPopup-title": "Crear un campo",
"current": "actual",
"custom-color": "Custom color",
"custom-field-delete-pop": "Se eliminará este campo personalizado de todas las tarjetas y se destruirá su historial. Esta acción no puede deshacerse.",
"custom-field-checkbox": "Casilla de verificación",
"custom-field-currency": "Moneda",
@@ -582,6 +584,7 @@
"fullname": "Nombre completo",
"header-logo-title": "Volver a tu página de tableros",
"show-activities": "Mostrar actividades",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Crear tablero",
"home": "Inicio",
"import": "Importar",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Aktsepteeri",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Loo väli",
"createCustomFieldPopup-title": "Loo väli",
"current": "praegune",
"custom-color": "Custom color",
"custom-field-delete-pop": "Tagasivõtmist ei ole võimalik teha. See eemaldab selle kohandatud välja kõikidest kaartidest ja hävitab selle ajaloo.",
"custom-field-checkbox": "Kontrollkast",
"custom-field-currency": "Valuuta",
@@ -582,6 +584,7 @@
"fullname": "Täielik nimi",
"header-logo-title": "Mine tagasi oma foorumite lehele.",
"show-activities": "Show Activities",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Loo juhatus",
"home": "Kodu",
"import": "Import",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "Trigger",
"r-action": "Tegevus",
"r-when-a-card": "Kui kaart",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "Ados",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "Sortu eremua",
"createCustomFieldPopup-title": "Sortu eremua",
"current": "unekoa",
"custom-color": "Custom color",
"custom-field-delete-pop": "Ez du atzera bueltarik. Honek eremu pertsonalizatua txartel guztietatik kenduko du eta bere historia ezabatuko du.",
"custom-field-checkbox": "Kontrol-laukia",
"custom-field-currency": "Moneta",
@@ -582,6 +584,7 @@
"fullname": "Izen abizenak",
"header-logo-title": "Itzuli zure arbelen orrira.",
"show-activities": "Erakutsi jarduerak",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "Sortu arbela",
"home": "Hasiera",
"import": "Inportatu",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "disparador",
"r-action": "acción",
"r-when-a-card": "Cuando una tarjeta",
+20
View File
@@ -1,6 +1,7 @@
{
"accept": "پذیرفتن",
"activity-changedTitle": "changed title to %s of %s",
"activity-changedDescription": "changed description of %s",
"act-deleteCard": "deleted card __card__ from list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoard": "deleted board __board__",
"act-removeList": "deleted list __list__ at board __board__",
@@ -441,6 +442,7 @@
"createCustomField": "ایجاد فیلد",
"createCustomFieldPopup-title": "ایجاد فیلد",
"current": "جاری",
"custom-color": "Custom color",
"custom-field-delete-pop": "این اقدام فیلد سفارشی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
"custom-field-checkbox": "جعبه انتخابی",
"custom-field-currency": "واحد پولی",
@@ -582,6 +584,7 @@
"fullname": "نام و نام خانوادگی",
"header-logo-title": "بازگشت به صفحه بردها.",
"show-activities": "نمایش فعالیت ها",
"hide-activities": "Hide Activities",
"headerBarCreateBoardPopup-title": "ایجاد برد",
"home": "خانه",
"import": "وارد کردن",
@@ -1016,6 +1019,17 @@
"r-workflow-help": "Drag a trigger and an action into the builder, then add the rule. Drag an action onto an existing rule to change what it does.",
"r-drop-trigger": "drop a trigger here",
"r-drop-action": "drop an action here",
"r-w-card-created": "Card is created",
"r-w-card-archived": "Card is archived",
"r-w-card-unarchived": "Card is unarchived",
"r-w-label-added": "Any label is added",
"r-w-label-removed": "Any label is removed",
"r-w-member-added": "A member is added",
"r-w-member-removed": "A member is removed",
"r-w-checklist-added": "A checklist is added",
"r-w-attachment-added": "An attachment is added",
"r-w-every-day-at": "Every day at __time__",
"r-w-set-received-now": "Set received date to now",
"r-export-json": "Export rules to JSON",
"r-export-csv": "Export rules to CSV",
"r-import-json": "Import rules from JSON",
@@ -1069,6 +1083,12 @@
"r-mark-incomplete": "Mark card incomplete",
"r-move-all-cards": "Move all cards in list",
"r-set-date-relative": "Set date relative to now",
"r-later": "later",
"r-unit-minutes": "minute(s)",
"r-unit-hours": "hour(s)",
"r-unit-days": "day(s)",
"r-unit-weeks": "week(s)",
"r-unit-months": "month(s)",
"r-trigger": "تریگر",
"r-action": "عملیات",
"r-when-a-card": "زمانی که کارت",
Loaded 100 of 280 files, more files were not shown because too many files have changed in this diff. Show more