iobroker.kanban 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +224 -0
  3. package/admin/i18n/de.json +100 -0
  4. package/admin/i18n/en.json +100 -0
  5. package/admin/i18n/es.json +100 -0
  6. package/admin/i18n/fr.json +100 -0
  7. package/admin/i18n/it.json +100 -0
  8. package/admin/i18n/nl.json +100 -0
  9. package/admin/i18n/pl.json +100 -0
  10. package/admin/i18n/pt.json +100 -0
  11. package/admin/i18n/ru.json +100 -0
  12. package/admin/i18n/uk.json +100 -0
  13. package/admin/i18n/zh-cn.json +100 -0
  14. package/admin/jsonConfig.json +668 -0
  15. package/admin/kanban.png +0 -0
  16. package/io-package.json +299 -0
  17. package/lib/cron.js +203 -0
  18. package/lib/dueat.js +77 -0
  19. package/lib/events.js +24 -0
  20. package/lib/holidays.js +167 -0
  21. package/lib/i18n-server.js +301 -0
  22. package/lib/notify.js +627 -0
  23. package/lib/scheduler.js +198 -0
  24. package/lib/server.js +799 -0
  25. package/lib/store.js +1500 -0
  26. package/main.js +382 -0
  27. package/package.json +58 -0
  28. package/www/css/app.css +1022 -0
  29. package/www/i18n/de.json +238 -0
  30. package/www/i18n/en.json +238 -0
  31. package/www/i18n/es.json +238 -0
  32. package/www/i18n/fr.json +238 -0
  33. package/www/i18n/it.json +238 -0
  34. package/www/i18n/nl.json +238 -0
  35. package/www/i18n/pl.json +238 -0
  36. package/www/i18n/pt.json +238 -0
  37. package/www/i18n/ru.json +238 -0
  38. package/www/i18n/uk.json +238 -0
  39. package/www/i18n/zh-cn.json +238 -0
  40. package/www/index.html +171 -0
  41. package/www/js/api.js +98 -0
  42. package/www/js/app.js +411 -0
  43. package/www/js/board.js +983 -0
  44. package/www/js/colorpicker.js +165 -0
  45. package/www/js/dialogs.js +1419 -0
  46. package/www/js/i18n.js +43 -0
  47. package/www/vendor/marked.min.js +69 -0
  48. package/www/vendor/purify.min.js +3 -0
  49. package/www/vendor/sortable.min.js +2 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Björn Müller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # ioBroker.kanban
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/iobroker.kanban.svg)](https://www.npmjs.com/package/iobroker.kanban)
4
+ [![Downloads](https://img.shields.io/npm/dm/iobroker.kanban.svg)](https://www.npmjs.com/package/iobroker.kanban)
5
+ ![Number of Installations](https://iobroker.live/badges/kanban-installed.svg)
6
+ ![Current version in stable repository](https://iobroker.live/badges/kanban-stable.svg)
7
+ [![Test and Release](https://github.com/bmueller77/ioBroker.kanban/actions/workflows/test-and-release.yml/badge.svg)](https://github.com/bmueller77/ioBroker.kanban/actions/workflows/test-and-release.yml)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+
10
+ Kanban board adapter for ioBroker with its **own web server**, live sync, webhooks, multi-user support and e-mail notifications (including calendar invites) via the `email` adapter.
11
+
12
+ ![Kanban board](docs/en/img/board.png)
13
+
14
+ 📖 **Full documentation:** [English](docs/en/README.md) · [Deutsch](docs/de/README.md)
15
+
16
+ ## Installation
17
+
18
+ Install the adapter from the ioBroker admin: *Adapters* → filter for `kanban` → install. Then create an instance `kanban.0` and open the web UI at `http://<host>:8095/`.
19
+
20
+ > The adapter is awaiting inclusion in the official ioBroker repository.
21
+
22
+ ## Features
23
+
24
+ - **Own web server** (default port 8095), the web UI is served directly by the adapter; no `iobroker upload` needed for UI updates
25
+ - **Multiple boards** with freely configurable columns (name, order, display limit, WIP limit, "new"/"done" flags)
26
+ - **Cards** with title, Markdown description, assignees, due date (optionally with time), labels, color, priority, checklist, link, location and calendar invite
27
+ - **Recurring tasks** (daily/weekly/monthly/yearly, n-th weekday, n-th working day incl. public-holiday calculation)
28
+ - **Drag & drop** (mouse + touch), live sync across all open views via WebSocket (polling fallback)
29
+ - **Multi-user without login**: user registry in the admin config, assignable members per board; the header chips act as a saved per-board person filter
30
+ - **E-mail notifications** via `iobroker.email` on assignment, due date and card events (toggleable per event type and per user)
31
+ - **Webhooks inbound** (token-secured) and **outbound** (JSON POST on events)
32
+ - **Share view**: dialog to build filtered, embeddable links
33
+ - **iframe-friendly** (no frame headers) with `?embed=1` mode for Lovelace & co.
34
+ - **Multilingual** (de, en, fr, nl, it, es, pl, pt, ru, uk, zh-cn), configurable **date & time format** per instance (moment/Day.js tokens with localised month/weekday names, 12h/24h), theming (light/dark/auto, accent color, custom CSS)
35
+
36
+ ## Web UI / URL parameters
37
+
38
+ `http://<host>:8095/` with optional parameters (excerpt, full list in the [docs](docs/en/README.md#sharing-views--url-parameters)):
39
+
40
+ | Parameter | Effect |
41
+ |---|---|
42
+ | `board=<id>` | preselect a board |
43
+ | `users=<name,name>` | person filter: show only cards assigned to these users (`user=<name>` = single-user short form) |
44
+ | `label=<id,id>` | label **blacklist**: hide cards with these labels |
45
+ | `columns=<id,id>` | show only these columns |
46
+ | `doneLimit=N` | in done columns show only N cards (`0` = none, omit = all) |
47
+ | `theme=light\|dark\|auto` | force a theme |
48
+ | `embed=1` | borderless view without the header bar (for iframes) |
49
+ | `card=<id>` | open a card dialog directly (deep link from e-mails) |
50
+ | `lang=<code>` | force a language (de, en, fr, nl, it, es, pl, pt, ru, uk, zh-cn) |
51
+
52
+ ### Lovelace embedding
53
+
54
+ ```yaml
55
+ type: iframe
56
+ url: http://<host>:8095/?board=family&embed=1&theme=auto&user=user1
57
+ aspect_ratio: 75%
58
+ ```
59
+
60
+ ## REST API
61
+
62
+ For integrations on the local network (the same API the web UI uses). **Reading** (`GET`) is open; **writing** (`POST`/`PATCH`/`DELETE`) requires a token from 0.1.1 (`X-Kanban-Token`; the web UI sends it automatically), see [Security](docs/en/README.md#security--access-control).
63
+
64
+ | Method | Route | Purpose |
65
+ |---|---|---|
66
+ | GET | `/api/boards` | board list |
67
+ | POST | `/api/boards` | create a board `{title}` |
68
+ | GET | `/api/boards/:id` | board JSON; with `?rev=<n>` → `{unchanged:true}` if current |
69
+ | PATCH | `/api/boards/:id` | `{title?, columns?, labels?}` |
70
+ | DELETE | `/api/boards/:id` | delete a board |
71
+ | POST | `/api/boards/:id/cards` | create a card |
72
+ | PATCH | `/api/boards/:id/cards/:cardId` | update a card partially |
73
+ | POST | `/api/boards/:id/cards/:cardId/move` | `{columnId, order?}` |
74
+ | DELETE | `/api/boards/:id/cards/:cardId` | delete a card |
75
+ | PATCH | `/api/users/:name` | set a user colour (applied at runtime, no restart) |
76
+
77
+ ## Webhooks & commands
78
+
79
+ External systems (scripts, agents) modify boards/cards token-secured via `POST /webhook/<token>/action`. The same command vocabulary applies as for `sendTo` and the `action` state:
80
+
81
+ ```bash
82
+ curl -X POST http://<host>:8095/webhook/<token>/action \
83
+ -H 'Content-Type: application/json' \
84
+ -d '{"cmd":"addCard","board":"family","title":"Buy milk","assignees":["user1"],"due":"2026-07-15"}'
85
+ ```
86
+
87
+ Commands: `listBoards`, `getBoard`, `addBoard`, `deleteBoard`, `addCard`, `updateCard`, `moveCard`, `doneCard`, `deleteCard`. From ioBroker scripts:
88
+
89
+ ```js
90
+ sendTo('kanban.0', 'addCard', { board: 'family', title: 'From a script' }, res => log(JSON.stringify(res)));
91
+ setState('kanban.0.action', JSON.stringify({ cmd: 'doneCard', board: 'family', cardId: 'c_xyz' }));
92
+ ```
93
+
94
+ **Outbound webhooks** send a JSON POST to configured URLs on events (`cardCreated, cardUpdated, cardMoved, cardAssigned, cardDone, cardDeleted, cardDue`). Details in the [docs](docs/en/README.md#webhooks-inbound).
95
+
96
+ ## States (for scripts/visualization)
97
+
98
+ | State | Content |
99
+ |---|---|
100
+ | `kanban.0.boards.<id>.data` | full board as JSON (read-only) |
101
+ | `kanban.0.boards.<id>.rev` / `.cardCount` / `.overdueCount` | revision & counters |
102
+ | `kanban.0.users.<name>.assignedCount` / `.overdueCount` / `.overdueList` | per user |
103
+ | `kanban.0.lastEvent` | last event as JSON (can trigger scripts) |
104
+ | `kanban.0.action` | command input (write JSON, cleared after processing) |
105
+
106
+ ## Security
107
+
108
+ From **0.1.1**: token-secured write API, Markdown preview sanitized with DOMPurify (no stored XSS), a Content Security Policy and safe link schemes only. The web UI works without a login, the token blocks third-party websites/CSRF but is **not** a substitute for network isolation. For hard isolation, bind the port to the LAN only or put an authenticating reverse proxy in front.
109
+
110
+ Also from **0.3.0**: agent tokens keep their board restriction on the REST API as well, tokens are only read from the header or the request body, the write secret lives in the adapter's file storage instead of a readable state, the token-free `action` state can be switched off, and irreversible commands are logged with their source. Note that `sendTo` and the `action` state are local ioBroker interfaces without a token by design: anyone who can run scripts in ioBroker can use them.
111
+
112
+ Details: [Security & access control](docs/en/README.md#security--access-control).
113
+
114
+ ## Requirements
115
+
116
+ - js-controller ≥ 6.0.11, Node.js ≥ 22
117
+ - For e-mail notifications: a configured `iobroker.email` instance
118
+ - Optional: `iobroker.feiertage` for region-accurate public-holiday calculation of the working-day recurrences
119
+
120
+ ## Changelog
121
+
122
+ ### 0.3.0 (2026-08-04)
123
+ * (bmueller77) **Trash**: deleting a card no longer removes it immediately, it moves to a per-board **Trash** column and can be restored for **30 days**, after which it is deleted permanently. The trash column is hidden by default and can be shown per device (board settings). It has its own fixed grey styling, is sorted by deletion time and shows the remaining days per card
124
+ * (bmueller77) Optional **automatic cleanup** of old done cards per board, by **age** (default 90 days) or by **count** (default 100), moving them into the trash daily and on adapter start
125
+ * (bmueller77) **Per-column sorting**: a toggle in the column header opens a menu with five modes, drag & drop, drag handles, due date (incl. time, cards without a date last), priority and age in column (most recently added on top, e.g. the last card you completed). For the automatic modes a **direction toggle** sits next to it and reverses the order with one click. Mode and direction are stored per device; returning to the manual modes restores your own order. Requested by @lyc in the [ioBroker forum](https://forum.iobroker.net/topic/85030/neuer-adapter-kanban-board) (post #5), tracked as [#10](https://github.com/bmueller77/iobroker.kanban/issues/10)
126
+ * (bmueller77) Cards can be **moved or copied to another board**: labels are matched by name, assignees are limited to members of the target board, and if none remain you are asked to pick one. Requested by @lyc in the [ioBroker forum](https://forum.iobroker.net/topic/85030/neuer-adapter-kanban-board) (post #5), tracked as [#11](https://github.com/bmueller77/iobroker.kanban/issues/11)
127
+ * (bmueller77) The same dialog can **clone a card in place**: three buttons at the top (clone / copy / move) decide what happens, and a clone duplicates the card with all its content directly below the original
128
+ * (bmueller77) **Recurrence by cron expression**: a new recurrence type takes the usual five fields (`0 8 * * 1-5`) with lists, ranges, steps and the English short names for month and weekday. The expression works as a pattern, not as a schedule: the adapter uses it to find the next due date when a card is ticked off. Minute and hour set the time of the card, and the editor shows the rule in plain words plus the next three dates while you type. Simple patterns also become a proper recurring calendar invitation
129
+ * (bmueller77) Recurring cards now produce a **series invite** (`RRULE`) instead of one single event per instance, and the invite is sent **once**: follow-up cards attach nothing, an updated invite (same `UID`, higher `SEQUENCE`) only follows a change of due date, time, duration or recurrence rule
130
+ * (bmueller77) Calendar invites get an adjustable **duration** (`calendarDuration`, `HH:MM`, default one hour) next to the calendar checkbox
131
+ * (bmueller77) Done cards now show a **strikethrough title**, a **completion timestamp** in the configured date/time format, and a **copy button** that opens the editor with the same content
132
+ * (bmueller77) The **"Email" tab is now called "Notifications"** and is sorted so that the mail settings come first: adapter instance, sender, reminder time, lead time, the card-precise due trigger, then the per-event defaults. The pointer to other services (Telegram, Pushover and the rest through the lastEvent state or an outbound webhook) sat in the middle of the mail settings and now closes the tab under its own heading, linking straight to the docs section that walks through it. Native messenger support stays open as [#12](https://github.com/bmueller77/iobroker.kanban/issues/12), raised by @lyc in the [ioBroker forum](https://forum.iobroker.net/topic/85030/neuer-adapter-kanban-board) (posts #5 and #6)
133
+ * (bmueller77) New events **cardRestored** and **cardPurged**; `cardDeleted` now means "moved to trash" (automatic cleanup adds `detail.auto`). Per-user e-mail toggles for all three; automatic cleanup runs are bundled into one summary e-mail per user
134
+ * (bmueller77) The **created** notification now reaches all members of the board instead of only the assignees of the card, so you also hear about cards someone else is responsible for
135
+ * (bmueller77) Every notification event and every card returned by the **REST API** now carries the computed field **`dueAt`**, the due date including time as an ISO timestamp with local offset (no time = 00:00), so automations no longer need to combine `due` + `dueTime` + time zone themselves
136
+ * (bmueller77) New instance option **"fire 'card due' at the card's time of day"** (off by default): cards with a time of day trigger `cardDue` exactly then, flagged `detail.exact: true`, next to the unchanged daily reminder, for minute-precise triggers without polling
137
+ * (bmueller77) Reworked **board settings**: one Board tab with a board picker (edit any board without switching), a "show this board" button, create/delete board, member selection and the cleanup section
138
+ * (bmueller77) Reworked **card editor layout**: calendar-invite checkbox and location moved up below the due date; assignees and labels sit side by side (stacked on narrow screens)
139
+ * (bmueller77) All irreversible actions now use an **in-app confirmation dialog** instead of the browser's `confirm()`
140
+ * (bmueller77) The card editor now opens **only via the edit icon** placed right after the end of the title, not by clicking anywhere on the card, so no editor opens by accident while scrolling or tapping. Cards stay draggable everywhere
141
+ * (bmueller77) Checklist items in the card editor can be **reordered by drag & drop** via a small grip (shown from two items upwards)
142
+ * (bmueller77) The **hit area of the checklist chevron** is noticeably wider and taller (the icon itself keeps its size and position), and whether a checklist is **expanded or collapsed is remembered** per device and board, just like the column sort modes
143
+ * (bmueller77) Columns always share the **full window width**; the board only scrolls horizontally once less than 280 px per column would be left
144
+ * (bmueller77) The landing zones offered while dragging on narrow screens moved from a column at the right edge, up to a full screen width away from the card, to a row along the top in the same order as the columns; with many columns the row wraps instead of running off screen
145
+ * (bmueller77) The address bar now carries the **current board** (`?board=<id>`), updated whenever you switch boards, so the URL can be copied and shared as is
146
+ * (bmueller77) New URL parameter **`onlyLabel=`** (label whitelist) next to the existing `label=` blacklist, selectable in the share dialog: show only cards carrying one of the given labels
147
+ * (bmueller77) Subtle depth for the board, all lit from the top left: cards, avatars, chips, header controls and buttons cast a
148
+ shadow to the bottom right, while columns, the card counter and chips of hidden users look recessed. Cards and
149
+ columns also carry a faint top-to-bottom gradient. Every effect is a CSS variable and can be overridden or
150
+ switched off in your own CSS
151
+ * (bmueller77) The UI now ships in **eleven languages**: German, English, French, Dutch, Italian, Spanish, Polish, Portuguese, Russian, Ukrainian and Chinese (simplified)
152
+ * (bmueller77) All **log messages are now in English** (they were partly German before), following the usual ioBroker convention. Texts in the web UI and in the admin config stay translated
153
+ * (bmueller77) **Security: the write token was readable by any website.** `Access-Control-Allow-Origin: *` sat on every route, including the one that hands the token to the UI in a `<meta>` tag, so any page open in your browser could scan the network for the adapter, read that page cross-origin, take the token and then change or delete boards. CORS is now limited to `/api` and `/webhook` and to origins listed in the new **"Allowed browser origins"** setting (empty by default = same origin only). Only browser access was affected; scripts, Node-RED and curl are unchanged
154
+ * (bmueller77) **Security: a board-restricted token could still escape its boards.** It was only checked for board-specific webhook calls and could change any board via `/api`. On the command route the guard accepted any allowed board named anywhere in the body as proof, even for commands that ignore that field: `addBoard` with `"board":"<allowed>"` created boards elsewhere, and the same trick worked on the user and avatar routes. What counts now is the board the call actually touches: the path board for REST plus a transfer's target, and per command the field that command really evaluates. A writing command that names no board is refused for restricted tokens; reading commands (`listBoards`, `getBoard`) stay open
155
+ * (bmueller77) **Security: an empty token row opened the API.** A row added in the token table but left blank matched every request that carried no token at all, because a missing token fell back to the empty string. Blank tokens are now rejected outright. In the same vein, an empty **"allowed boards"** field counted as `*`, so clearing it to take rights away in fact granted them for every board. Empty now means no board; enter `*` explicitly for all
156
+ * (bmueller77) Tokens are **no longer accepted as a URL parameter** (`?token=…`), only in the `X-Kanban-Token` header or as `_token` in the body, so they stop showing up in logs, browser history and referrers
157
+ * (bmueller77) The **SPA write secret moved into the adapter's file storage**; the state `kanban.0.info.apiSecret` stays but is kept empty. An existing value is migrated on first start. Object access no longer implies write access to the API
158
+ * (bmueller77) The **`action` state can be switched off** in the instance settings ("Webhooks (in)"). It executes the full command vocabulary without a token, so installations that do not use it can close that door
159
+ * (bmueller77) **Irreversible commands** (`deleteBoard`, `emptyTrash`, `purgeCard`) are logged with their source, no matter which route they came in through
160
+ * (bmueller77) **Fix: on a tablet, dragging a card into another column was cancelled by the context menu.** Dragging by touch means pressing and holding, which Android also reads as a long press. With the finger on an icon (priority, due date and location are SVGs) or on a link, the WebView opened its context menu, sent `pointercancel` and the card dropped back where it came from. Measured on a Galaxy Tab S5e: context menu after 251 ms, cancel after 749 ms. Grabbing the same card by its title worked, which is why it looked arbitrary: cards without a due date, priority or location have no icon row at all. The context menu is now suppressed on cards, and `touch-action` is applied to their children as well, since it does not inherit and the finger practically never rests on the card itself
161
+ * (bmueller77) **Fix: dragging a card landed it somewhere else while a filter was active.** The board reported the position among the *visible* cards, but the server reads it as a position in the *full* column. With a person or label filter, a display limit or a done limit in place, the card therefore jumped after the next reload. The position is now translated to the full column before it is sent
162
+ * (bmueller77) **Fix: the "views" dialog kept offering the users of the board you were looking at.** Switching the board inside the dialog reloaded labels and columns but not the users, so the generated `users=` link could name people who belong to no one on the target board, and then silently filtered nothing at all
163
+ * (bmueller77) **Fix: a board refresh could pull you back to the board you just left.** A reply that arrived after you had switched boards overwrote the new one, and two overlapping refreshes could write an older revision over a newer one
164
+ * (bmueller77) **Fix: a card spawned by a recurrence lost its time of day, location and calendar-invite flag.** They were silently dropped when the follow-up card was built, so `dueAt` of the new card was always 00:00. All three are inherited from the template now
165
+ * (bmueller77) **Fix: a board whose member list no longer matched any existing user became unusable.** After renaming user IDs in the admin, the board offered nobody while an assignee is a required field, so no card could be saved. Such a board now offers **all** users. User rows without an ID are dropped instead of showing up as a member called "null", and removing a member who is the only assignee of cards asks first
166
+ * (bmueller77) Fix: ticking a checklist item on a card no longer scrolls the board back to the top; column, board and page scroll positions survive the re-render
167
+ * (bmueller77) Fix: a shared `users=` link no longer overwrites the personal chip selection permanently
168
+ * (bmueller77) Fix: live sync reconnects reliably after an adapter restart (single reconnect chain, watchdog, refresh on tab focus and a minute-by-minute safety net)
169
+ * (bmueller77) Fix: native date and time pickers follow the theme (`color-scheme`), so the calendar icon stays visible in dark mode
170
+ * (bmueller77) Fix: the port fallback is logged as a warning instead of an error and says what to do
171
+ * (bmueller77) **Stricter validation, please check your automations.** The API no longer repairs invalid input silently: an unknown `columnId`, a malformed `due` and a `priority` outside `0/1/2` now return an error instead of being dropped or remapped, and `getBoard` on an unknown board answers `404` instead of `200` with `null`
172
+
173
+ ### 0.2.1 (2026-07-25)
174
+ * (bmueller77) Now runs on **Express 5** (updated dependency)
175
+ * (bmueller77) Fixed the **user avatar upload** ("image could not be read"): the Content-Security-Policy blocked the `blob:` URL used to read the file; the image is now loaded without a `blob:` URL, so the CSP stays strict
176
+ * (bmueller77) Requires **Node.js 20+** (Node.js 18 reached end-of-life) and **admin 7.8.23+**
177
+ * (bmueller77) Updated dependencies (`@iobroker/adapter-core`, `ws`)
178
+ * (bmueller77) Adapter metadata (type, connection type, keywords) and repository housekeeping for the ioBroker repository (adapter checker)
179
+ * (bmueller77) Every notification event now carries a ready-to-use deep **link** to the card; the docs gained copy-paste **Telegram/Pushover** notification-routing examples
180
+
181
+ ### 0.2.0 (2026-07-22)
182
+ * (bmueller77) Mobile: columns stack & collapse (accordion); full-screen dialogs with a fixed action bar (equal-width buttons), no sideways scrolling
183
+ * (bmueller77) Assignable **users per board**, managed centrally under *Settings → Boards*; each board needs at least one member
184
+ * (bmueller77) Header user chips are now a **saved, per-board filter** (multi-select; tap to show only those users' cards; all active by default). The old "my cards" button was removed
185
+ * (bmueller77) **User colours** are edited in the web UI (*Settings → Users*), applied instantly **without an adapter restart** (previously in the instance config)
186
+ * (bmueller77) **Colour ring** around avatars (cards always, chips when selected), 50% larger avatars, and **automatic black/white text** on labels & avatars (WCAG luminance) for readability
187
+ * (bmueller77) Per-board **notification link target**: board view (highlight card), card editor, or a fixed custom URL
188
+ * (bmueller77) **Configurable date format** per instance (moment/Day.js tokens incl. localised month/weekday names) plus a 12h/24h **time format**; empty date format = ioBroker system format
189
+ * (bmueller77) **At least one assignee is required** per card in the UI, required fields are marked with a red `*`; the validation message follows the board language
190
+ * (bmueller77) **Per-column display limit** ("Max"): show only the first N cards, the rest collapse into a `+X more` hint
191
+ * (bmueller77) Column settings gained an aligned header row (Title · Max · WIP · New · Done) with explanatory tooltips
192
+ * (bmueller77) Material Design icons throughout (toolbar, card badges, link types), no more emoji glyphs
193
+ - **0.1.3**, Fix: the column task count now respects the active person/label filter (previously showed the column total)
194
+ - **0.1.2**, "Share view": `doneLimit` distinguishes empty=all / 0=none; label filter is now a blacklist (new labels stay visible)
195
+ - **0.1.1**, Security: token-protected write API, sanitized Markdown preview, CSP, safe link schemes
196
+ - **0.1.0**, Initial release
197
+
198
+ ## Acknowledgements
199
+
200
+ Built with the support of Anthropic's **Claude**, in particular for the translations of the web UI and this documentation (English, French, Dutch, Italian), as well as testing and documentation review.
201
+
202
+ ## License
203
+
204
+ The MIT License (MIT)
205
+
206
+ Copyright (c) 2026 Björn Müller <bjoern@mueller.family>
207
+
208
+ Permission is hereby granted, free of charge, to any person obtaining a copy
209
+ of this software and associated documentation files (the "Software"), to deal
210
+ in the Software without restriction, including without limitation the rights
211
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
212
+ copies of the Software, and to permit persons to whom the Software is
213
+ furnished to do so, subject to the following conditions:
214
+
215
+ The above copyright notice and this permission notice shall be included in all
216
+ copies or substantial portions of the Software.
217
+
218
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
219
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
220
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
221
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
222
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
223
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
224
+ SOFTWARE.
@@ -0,0 +1,100 @@
1
+ {
2
+ "emailTab__hdr_text": "Vorgabe (gilt, wenn beim Benutzer nichts gesetzt ist)",
3
+ "emailTab__otherHdr_text": "Andere Dienste (Telegram, Pushover, …)",
4
+ "emailTab__otherServicesHint_text": "Eingebaut ist nur E-Mail. Jeder andere Dienst läuft über den lastEvent-State oder einen ausgehenden Webhook — die Doku zeigt das an einem Telegram-Skript zum Kopieren.",
5
+ "emailTab__otherServicesLink_label": "An Telegram, Pushover und andere schicken",
6
+ "emailTab_dueExact_help": "Zusätzlich zur täglichen Erinnerung: Karten mit Uhrzeit lösen cardDue genau dann aus (detail.exact = true). Achtung: Damit geht auch eine zweite „Fällig\"-E-Mail an alle raus, die diese Benachrichtigung aktiviert haben.",
7
+ "emailTab_dueExact_label": "„Karte fällig\" zur Uhrzeit der Karte auslösen",
8
+ "emailTab_emailFrom_label": "Absenderadresse (leer = Adapter-Vorgabe)",
9
+ "emailTab_emailInstance_label": "E-Mail-Adapter-Instanz",
10
+ "emailTab_label": "Benachrichtigungen",
11
+ "emailTab_notifyAssigned_label": "Karte zugewiesen",
12
+ "emailTab_notifyCreated_label": "Karte angelegt",
13
+ "emailTab_notifyDeleted_label": "In den Papierkorb",
14
+ "emailTab_notifyDone_label": "Karte erledigt",
15
+ "emailTab_notifyDue_label": "Karte fällig/überfällig",
16
+ "emailTab_notifyMoved_label": "Karte verschoben",
17
+ "emailTab_notifyPurged_label": "Endgültig gelöscht",
18
+ "emailTab_notifyRestored_label": "Karte wiederhergestellt",
19
+ "emailTab_notifyUpdated_label": "Karte geändert",
20
+ "emailTab_reminderDaysBefore_label": "X Tage vor Fälligkeit erinnern",
21
+ "emailTab_reminderTime_label": "Erinnerungs-Uhrzeit (HH:MM)",
22
+ "emailTab_reminderTime_validatorErrorText": "Bitte im Format HH:MM angeben, z. B. 07:30.",
23
+ "generalTab_accentColor_label": "Akzentfarbe",
24
+ "generalTab_bind_label": "IP-Adresse",
25
+ "generalTab_customCss_help": "Wird als letztes Stylesheet in der Board-Oberfläche geladen",
26
+ "generalTab_customCss_label": "Eigenes CSS",
27
+ "generalTab_dateFormat_help": "Leer = ioBroker-Systemformat. Platzhalter: D/DD Tag, M/MM Monat, MMM/MMMM Monatsname, YY/YYYY Jahr, ddd/dddd Wochentag (z.B. DD. MMMM YYYY)",
28
+ "generalTab_dateFormat_label": "Datumsformat",
29
+ "generalTab_label": "Allgemein",
30
+ "generalTab_language_help": "Leer/Automatisch = ioBroker-Systemsprache",
31
+ "generalTab_language_label": "Sprache",
32
+ "generalTab_language_options10_label": "Українська",
33
+ "generalTab_language_options11_label": "中文",
34
+ "generalTab_language_options6_label": "Español",
35
+ "generalTab_language_options7_label": "Polski",
36
+ "generalTab_language_options8_label": "Português",
37
+ "generalTab_language_options9_label": "Русский",
38
+ "generalTab_language_options_0_label": "Automatisch (System)",
39
+ "generalTab_language_options_1_label": "Deutsch",
40
+ "generalTab_language_options_2_label": "English",
41
+ "generalTab_language_options_3_label": "Français",
42
+ "generalTab_language_options_4_label": "Nederlands",
43
+ "generalTab_language_options_5_label": "Italiano",
44
+ "generalTab_port_label": "Port",
45
+ "generalTab_publicUrl_help": "z.B. http://192.168.1.10:8095 — leer = automatisch",
46
+ "generalTab_publicUrl_label": "Basis-URL (für Links in E-Mails)",
47
+ "generalTab_themeDefault_label": "Standard-Theme",
48
+ "generalTab_themeDefault_options_0_label": "Automatisch (System)",
49
+ "generalTab_themeDefault_options_1_label": "Hell",
50
+ "generalTab_themeDefault_options_2_label": "Dunkel",
51
+ "generalTab_timeFormat_label": "Uhrzeit-Format",
52
+ "generalTab_timeFormat_options_0_label": "24-Stunden (14:00)",
53
+ "generalTab_timeFormat_options_1_label": "12-Stunden (2:00 PM)",
54
+ "usersTab__info_text": "Benutzer können Karten zugewiesen werden. Kein Login — die Benutzer-Chips in der Board-Kopfzeile dienen als Filter.",
55
+ "usersTab__notifyInfo_text": "Nicht angehakt = globale Vorgabe (Tab „Benachrichtigungen\"). Eine E-Mail wird nur gesendet, wenn beim Benutzer eine Adresse hinterlegt und der Tab konfiguriert ist. Automatische Aufräumläufe werden zu einer Sammelmail je Benutzer gebündelt.",
56
+ "usersTab__notifyLegend_text": "<div style='font-size:0.85rem;line-height:1.5;opacity:0.85'><b>Was die Spalten bedeuten</b><table style='border-collapse:collapse'><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Zugew.</b></td><td>dem Benutzer wurde eine Karte zugewiesen, auch nachträglich bei einer bestehenden Karte</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Fällig</b></td><td>eine offene Karte des Benutzers ist fällig, überfällig oder rückt in die eingestellten Tage vor Fälligkeit. Die Erinnerung wiederholt sich täglich zur Erinnerungs-Uhrzeit</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Geänd.</b></td><td>eine Karte des Benutzers wurde bearbeitet</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Versch.</b></td><td>eine Karte des Benutzers wurde in eine andere Spalte verschoben</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Erled.</b></td><td>eine Karte des Benutzers wurde als erledigt markiert</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Neu</b></td><td>in einem Board, in dem der Benutzer Mitglied ist, wurde eine neue Karte angelegt, ganz gleich wer zuständig ist. Das gilt auch für Kopien aus einem anderen Board und für Folgekarten von Wiederholungen</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Papier.</b></td><td>eine Karte des Benutzers ist im Papierkorb gelandet, manuell oder durch das automatische Aufräumen. Dort bleibt sie 30 Tage wiederherstellbar</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Wiederh.</b></td><td>eine Karte des Benutzers wurde aus dem Papierkorb wiederhergestellt</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Gelöscht</b></td><td>eine Karte des Benutzers wurde nach den 30 Tagen endgültig gelöscht</td></tr></table></div>",
57
+ "usersTab_label": "Benutzer",
58
+ "usersTab_users_0_title": "ID (klein, ohne Umlaute)",
59
+ "usersTab_users_10_title": "→ Wiederh.",
60
+ "usersTab_users_10_tooltip": "E-Mail, wenn eine Karte dieses Benutzers aus dem Papierkorb zurückgeholt wird",
61
+ "usersTab_users_11_title": "→ Gelöscht",
62
+ "usersTab_users_11_tooltip": "E-Mail, wenn eine Karte dieses Benutzers endgültig gelöscht wird",
63
+ "usersTab_users_1_title": "Anzeigename",
64
+ "usersTab_users_2_title": "E-Mail",
65
+ "usersTab_users_3_title": "→ Zugew.",
66
+ "usersTab_users_3_tooltip": "E-Mail, wenn dem Benutzer eine Karte zugewiesen wird",
67
+ "usersTab_users_4_title": "→ Fällig",
68
+ "usersTab_users_4_tooltip": "E-Mail, wenn eine Karte des Benutzers fällig/überfällig ist",
69
+ "usersTab_users_5_title": "→ Geänd.",
70
+ "usersTab_users_5_tooltip": "E-Mail, wenn eine Karte des Benutzers bearbeitet wird",
71
+ "usersTab_users_6_title": "→ Versch.",
72
+ "usersTab_users_6_tooltip": "E-Mail, wenn eine Karte in eine andere Spalte wandert",
73
+ "usersTab_users_7_title": "→ Erled.",
74
+ "usersTab_users_7_tooltip": "E-Mail, wenn eine Karte als erledigt markiert wird",
75
+ "usersTab_users_8_title": "→ Neu",
76
+ "usersTab_users_8_tooltip": "E-Mail, wenn eine neue Karte angelegt wird",
77
+ "usersTab_users_9_title": "→ Papier.",
78
+ "usersTab_users_9_tooltip": "E-Mail, wenn eine Karte dieses Benutzers in den Papierkorb wandert (manuell oder durch Aufräumen)",
79
+ "usersTab_users_label": "Benutzer",
80
+ "webhookInTab__info_text": "Externe Systeme (Skripte, KI-Agenten, …) lesen und schreiben Karten via POST /webhook/<token>/action — Kommandos siehe README. Jede Integration sollte einen eigenen Token bekommen.",
81
+ "webhookInTab__scopeInfo_text": "Die Board-Begrenzung gilt für die Webhook-Route und für die REST-API: Ein auf Boards begrenzter Token kann keine anderen Boards ändern, keine Boards anlegen und keine Benutzer bearbeiten. Tokens werden nur noch im Header X-Kanban-Token oder als _token im Body angenommen — nicht mehr als URL-Parameter.",
82
+ "webhookInTab_actionStateEnabled_help": "Der action-State dieser Instanz führt dieselben Kommandos aus wie die Webhooks, auch deleteBoard und emptyTrash, und braucht keinen Token. Abschalten, wenn kein Skript darauf schreibt.",
83
+ "webhookInTab_actionStateEnabled_label": "Kommandos über den action-State annehmen",
84
+ "webhookInTab_corsOrigins_help": "Nur nötig für Webseiten anderer Herkunft, die die API aus dem Browser aufrufen, z. B. https://dashboard.local:8123 (mehrere per Komma). Leer = nur gleiche Herkunft, das ist die sichere Vorgabe. Skripte, Node-RED und curl sind davon nicht betroffen.",
85
+ "webhookInTab_corsOrigins_label": "Erlaubte Browser-Herkünfte (CORS)",
86
+ "webhookInTab_generateToken_label": "Neuen Token generieren",
87
+ "webhookInTab_inboundTokens_0_title": "Name",
88
+ "webhookInTab_inboundTokens_1_title": "Token",
89
+ "webhookInTab_inboundTokens_2_title": "Erlaubte Boards (Komma oder *)",
90
+ "webhookInTab_inboundTokens_3_title": "Aktiv",
91
+ "webhookInTab_inboundTokens_label": "Tokens",
92
+ "webhookInTab_label": "Webhooks (eingehend)",
93
+ "webhookOutTab__info_text": "Bei Ereignissen sendet der Adapter einen JSON-POST an diese URLs. Ereignisse: cardCreated, cardUpdated, cardMoved, cardAssigned, cardDone, cardDeleted, cardRestored, cardPurged, cardDue — oder * für alle. Jede Nachricht enthält dueAt (Fälligkeit mit Datum + Uhrzeit und lokalem Offset).",
94
+ "webhookOutTab_label": "Webhooks (ausgehend)",
95
+ "webhookOutTab_outboundWebhooks_0_title": "Name",
96
+ "webhookOutTab_outboundWebhooks_1_title": "URL",
97
+ "webhookOutTab_outboundWebhooks_2_title": "Ereignisse (Komma oder *)",
98
+ "webhookOutTab_outboundWebhooks_3_title": "Aktiv",
99
+ "webhookOutTab_outboundWebhooks_label": "Webhooks"
100
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "emailTab__hdr_text": "Default (used when a user has no own setting)",
3
+ "emailTab__otherHdr_text": "Other services (Telegram, Pushover, …)",
4
+ "emailTab__otherServicesHint_text": "Only e-mail is built in. Every other service goes through the lastEvent state or an outbound webhook — the docs walk through it with a Telegram script you can copy.",
5
+ "emailTab__otherServicesLink_label": "Send to Telegram, Pushover and others",
6
+ "emailTab_dueExact_help": "In addition to the daily reminder: cards with a time of day trigger cardDue exactly then (detail.exact = true). Note that this also sends a second \"due\" e-mail to everyone who has that notification enabled.",
7
+ "emailTab_dueExact_label": "Fire \"card due\" at the card’s time of day",
8
+ "emailTab_emailFrom_label": "Sender address (empty = adapter default)",
9
+ "emailTab_emailInstance_label": "Email adapter instance",
10
+ "emailTab_label": "Notifications",
11
+ "emailTab_notifyAssigned_label": "Card assigned",
12
+ "emailTab_notifyCreated_label": "Card created",
13
+ "emailTab_notifyDeleted_label": "Moved to trash",
14
+ "emailTab_notifyDone_label": "Card done",
15
+ "emailTab_notifyDue_label": "Card due/overdue",
16
+ "emailTab_notifyMoved_label": "Card moved",
17
+ "emailTab_notifyPurged_label": "Permanently deleted",
18
+ "emailTab_notifyRestored_label": "Card restored",
19
+ "emailTab_notifyUpdated_label": "Card changed",
20
+ "emailTab_reminderDaysBefore_label": "Remind X days before due",
21
+ "emailTab_reminderTime_label": "Reminder time (HH:MM)",
22
+ "emailTab_reminderTime_validatorErrorText": "Please use the format HH:MM, e.g. 07:30.",
23
+ "generalTab_accentColor_label": "Accent color",
24
+ "generalTab_bind_label": "Listen address",
25
+ "generalTab_customCss_help": "Loaded as last stylesheet in the board UI",
26
+ "generalTab_customCss_label": "Custom CSS",
27
+ "generalTab_dateFormat_help": "Empty = ioBroker system format. Tokens: D/DD day, M/MM month, MMM/MMMM month name, YY/YYYY year, ddd/dddd weekday (e.g. DD. MMMM YYYY)",
28
+ "generalTab_dateFormat_label": "Date format",
29
+ "generalTab_label": "General",
30
+ "generalTab_language_help": "Empty/Auto = ioBroker system language",
31
+ "generalTab_language_label": "Language",
32
+ "generalTab_language_options10_label": "Українська",
33
+ "generalTab_language_options11_label": "中文",
34
+ "generalTab_language_options6_label": "Español",
35
+ "generalTab_language_options7_label": "Polski",
36
+ "generalTab_language_options8_label": "Português",
37
+ "generalTab_language_options9_label": "Русский",
38
+ "generalTab_language_options_0_label": "Auto (system)",
39
+ "generalTab_language_options_1_label": "Deutsch",
40
+ "generalTab_language_options_2_label": "English",
41
+ "generalTab_language_options_3_label": "Français",
42
+ "generalTab_language_options_4_label": "Nederlands",
43
+ "generalTab_language_options_5_label": "Italiano",
44
+ "generalTab_port_label": "Port",
45
+ "generalTab_publicUrl_help": "e.g. http://192.168.1.10:8095 — empty = auto-detect",
46
+ "generalTab_publicUrl_label": "Public base URL (for email links)",
47
+ "generalTab_themeDefault_label": "Default theme",
48
+ "generalTab_themeDefault_options_0_label": "Auto (system)",
49
+ "generalTab_themeDefault_options_1_label": "Light",
50
+ "generalTab_themeDefault_options_2_label": "Dark",
51
+ "generalTab_timeFormat_label": "Time format",
52
+ "generalTab_timeFormat_options_0_label": "24-hour (14:00)",
53
+ "generalTab_timeFormat_options_1_label": "12-hour (2:00 PM)",
54
+ "usersTab__info_text": "Users can be assigned to cards. No login — the user chips in the board header act as a filter.",
55
+ "usersTab__notifyInfo_text": "Leave a box unchecked to use the global default (Notifications tab). An e-mail is only sent if the user has an address and the Notifications tab is configured. Automatic cleanup runs are bundled into a single summary e-mail per user.",
56
+ "usersTab__notifyLegend_text": "<div style='font-size:0.85rem;line-height:1.5;opacity:0.85'><b>What the columns mean</b><table style='border-collapse:collapse'><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ assigned</b></td><td>a card was assigned to this user, including later on an existing card</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ due</b></td><td>an open card of this user is due, overdue or enters the configured days before the due date. The reminder repeats daily at the reminder time</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ changed</b></td><td>a card of this user was edited</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ moved</b></td><td>a card of this user was moved to another column</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ done</b></td><td>a card of this user was marked done</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ created</b></td><td>a new card was created on a board this user is a member of, no matter who it is assigned to. This also covers copies from another board and follow-up cards of a recurrence</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ trash</b></td><td>a card of this user went to the trash, manually or through the automatic cleanup. It stays restorable for 30 days</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ restored</b></td><td>a card of this user was restored from the trash</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ deleted</b></td><td>a card of this user was deleted permanently after the 30 days</td></tr></table></div>",
57
+ "usersTab_label": "Users",
58
+ "usersTab_users_0_title": "ID (lowercase)",
59
+ "usersTab_users_10_title": "→ restored",
60
+ "usersTab_users_10_tooltip": "E-mail when a card of this user is restored from the trash",
61
+ "usersTab_users_11_title": "→ deleted",
62
+ "usersTab_users_11_tooltip": "E-mail when a card of this user is permanently deleted",
63
+ "usersTab_users_1_title": "Display name",
64
+ "usersTab_users_2_title": "Email",
65
+ "usersTab_users_3_title": "→ assigned",
66
+ "usersTab_users_3_tooltip": "E-mail when a card is assigned to this user",
67
+ "usersTab_users_4_title": "→ due",
68
+ "usersTab_users_4_tooltip": "E-mail when a card of this user is due/overdue",
69
+ "usersTab_users_5_title": "→ changed",
70
+ "usersTab_users_5_tooltip": "E-mail when a card of this user is edited",
71
+ "usersTab_users_6_title": "→ moved",
72
+ "usersTab_users_6_tooltip": "E-mail when a card is moved to another column",
73
+ "usersTab_users_7_title": "→ done",
74
+ "usersTab_users_7_tooltip": "E-mail when a card is marked done",
75
+ "usersTab_users_8_title": "→ created",
76
+ "usersTab_users_8_tooltip": "E-mail when a new card is created",
77
+ "usersTab_users_9_title": "→ trash",
78
+ "usersTab_users_9_tooltip": "E-mail when a card of this user is moved to the trash (manually or by cleanup)",
79
+ "usersTab_users_label": "Users",
80
+ "webhookInTab__info_text": "External systems (scripts, AI agents, …) read and write cards via POST /webhook/<token>/action — see README for the command vocabulary. Each integration should get its own token.",
81
+ "webhookInTab__scopeInfo_text": "The board restriction applies to the webhook route and to the REST API: a token limited to specific boards cannot change other boards, create boards or edit users. Tokens are only accepted in the X-Kanban-Token header or as _token in the body — no longer as a URL parameter.",
82
+ "webhookInTab_actionStateEnabled_help": "The action state of this instance executes the same commands as the webhooks, including deleteBoard and emptyTrash, and requires no token. Turn this off if no script writes to it.",
83
+ "webhookInTab_actionStateEnabled_label": "Accept commands via the action state",
84
+ "webhookInTab_corsOrigins_help": "Only needed for web pages on another origin that call the API from the browser, e.g. https://dashboard.local:8123 (comma-separated). Empty = same origin only, which is the safe default. Scripts, Node-RED and curl are not affected.",
85
+ "webhookInTab_corsOrigins_label": "Allowed browser origins (CORS)",
86
+ "webhookInTab_generateToken_label": "Generate new token",
87
+ "webhookInTab_inboundTokens_0_title": "Name",
88
+ "webhookInTab_inboundTokens_1_title": "Token",
89
+ "webhookInTab_inboundTokens_2_title": "Allowed boards (comma or *)",
90
+ "webhookInTab_inboundTokens_3_title": "Enabled",
91
+ "webhookInTab_inboundTokens_label": "Tokens",
92
+ "webhookInTab_label": "Webhooks (in)",
93
+ "webhookOutTab__info_text": "On events the adapter POSTs a JSON payload to these URLs. Events: cardCreated, cardUpdated, cardMoved, cardAssigned, cardDone, cardDeleted, cardRestored, cardPurged, cardDue — or * for all. Each payload includes dueAt (due date + time with local offset).",
94
+ "webhookOutTab_label": "Webhooks (out)",
95
+ "webhookOutTab_outboundWebhooks_0_title": "Name",
96
+ "webhookOutTab_outboundWebhooks_1_title": "URL",
97
+ "webhookOutTab_outboundWebhooks_2_title": "Events (comma or *)",
98
+ "webhookOutTab_outboundWebhooks_3_title": "Enabled",
99
+ "webhookOutTab_outboundWebhooks_label": "Webhooks"
100
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "emailTab__hdr_text": "Predeterminado (se aplica si el usuario no tiene ajuste propio)",
3
+ "emailTab__otherHdr_text": "Otros servicios (Telegram, Pushover, …)",
4
+ "emailTab__otherServicesHint_text": "Solo el correo está integrado. Cualquier otro servicio pasa por el estado lastEvent o por un webhook saliente — la documentación lo muestra con un script de Telegram para copiar.",
5
+ "emailTab__otherServicesLink_label": "Enviar a Telegram, Pushover y otros",
6
+ "emailTab_dueExact_help": "Además del recordatorio diario: las tarjetas con hora disparan cardDue justo entonces (detail.exact = true). Tenga en cuenta que así sale también un segundo correo de «vencimiento» a todos los que tengan activada esa notificación.",
7
+ "emailTab_dueExact_label": "Lanzar «tarjeta vence» a la hora indicada en la tarjeta",
8
+ "emailTab_emailFrom_label": "Dirección del remitente (vacío = valor del adaptador)",
9
+ "emailTab_emailInstance_label": "Instancia del adaptador de correo",
10
+ "emailTab_label": "Notificaciones",
11
+ "emailTab_notifyAssigned_label": "Tarjeta asignada",
12
+ "emailTab_notifyCreated_label": "Tarjeta creada",
13
+ "emailTab_notifyDeleted_label": "Movida a la papelera",
14
+ "emailTab_notifyDone_label": "Tarjeta hecha",
15
+ "emailTab_notifyDue_label": "Tarjeta vence/atrasada",
16
+ "emailTab_notifyMoved_label": "Tarjeta movida",
17
+ "emailTab_notifyPurged_label": "Eliminada definitivamente",
18
+ "emailTab_notifyRestored_label": "Tarjeta restaurada",
19
+ "emailTab_notifyUpdated_label": "Tarjeta modificada",
20
+ "emailTab_reminderDaysBefore_label": "Recordar X días antes del vencimiento",
21
+ "emailTab_reminderTime_label": "Hora del recordatorio (HH:MM)",
22
+ "emailTab_reminderTime_validatorErrorText": "Use el formato HH:MM, p. ej. 07:30.",
23
+ "generalTab_accentColor_label": "Color de acento",
24
+ "generalTab_bind_label": "Dirección de escucha",
25
+ "generalTab_customCss_help": "Se carga como última hoja de estilos en la interfaz del tablero",
26
+ "generalTab_customCss_label": "CSS personalizado",
27
+ "generalTab_dateFormat_help": "Vacío = formato del sistema ioBroker. Comodines: D/DD día, M/MM mes, MMM/MMMM nombre del mes, YY/YYYY año, ddd/dddd día de la semana (p. ej. DD. MMMM YYYY)",
28
+ "generalTab_dateFormat_label": "Formato de fecha",
29
+ "generalTab_label": "General",
30
+ "generalTab_language_help": "Vacío/Automático = idioma del sistema ioBroker",
31
+ "generalTab_language_label": "Idioma",
32
+ "generalTab_language_options10_label": "Українська",
33
+ "generalTab_language_options11_label": "中文",
34
+ "generalTab_language_options6_label": "Español",
35
+ "generalTab_language_options7_label": "Polski",
36
+ "generalTab_language_options8_label": "Português",
37
+ "generalTab_language_options9_label": "Русский",
38
+ "generalTab_language_options_0_label": "Automático (sistema)",
39
+ "generalTab_language_options_1_label": "Deutsch",
40
+ "generalTab_language_options_2_label": "English",
41
+ "generalTab_language_options_3_label": "Français",
42
+ "generalTab_language_options_4_label": "Nederlands",
43
+ "generalTab_language_options_5_label": "Italiano",
44
+ "generalTab_port_label": "Puerto",
45
+ "generalTab_publicUrl_help": "p. ej. http://192.168.1.10:8095 — vacío = detección automática",
46
+ "generalTab_publicUrl_label": "URL base pública (para enlaces en correos)",
47
+ "generalTab_themeDefault_label": "Tema predeterminado",
48
+ "generalTab_themeDefault_options_0_label": "Automático (sistema)",
49
+ "generalTab_themeDefault_options_1_label": "Claro",
50
+ "generalTab_themeDefault_options_2_label": "Oscuro",
51
+ "generalTab_timeFormat_label": "Formato de hora",
52
+ "generalTab_timeFormat_options_0_label": "24 horas (14:00)",
53
+ "generalTab_timeFormat_options_1_label": "12 horas (2:00 PM)",
54
+ "usersTab__info_text": "Los usuarios pueden asignarse a tarjetas. Sin inicio de sesión — las fichas de usuario en la cabecera del tablero actúan como filtro.",
55
+ "usersTab__notifyInfo_text": "Sin marcar = valor global por defecto (pestaña «Notificaciones»). Solo se envía correo si el usuario tiene dirección y la pestaña está configurada. Las limpiezas automáticas se agrupan en un único correo resumen por usuario.",
56
+ "usersTab__notifyLegend_text": "<div style='font-size:0.85rem;line-height:1.5;opacity:0.85'><b>Qué significan las columnas</b><table style='border-collapse:collapse'><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Asignada</b></td><td>se asignó una tarjeta al usuario, también posteriormente en una tarjeta existente</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Vence</b></td><td>una tarjeta abierta del usuario vence, está atrasada o entra en los días configurados antes del vencimiento. El recordatorio se repite a diario a la hora indicada</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Modificada</b></td><td>se editó una tarjeta del usuario</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Movida</b></td><td>una tarjeta del usuario se movió a otra columna</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Hecha</b></td><td>una tarjeta del usuario se marcó como hecha</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Creada</b></td><td>se creó una tarjeta nueva en un tablero del que el usuario es miembro, sin importar a quién esté asignada. Esto incluye copias de otro tablero y tarjetas siguientes de una recurrencia</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Papelera</b></td><td>una tarjeta del usuario fue a la papelera, manualmente o por la limpieza automática. Sigue siendo restaurable durante 30 días</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Restaurada</b></td><td>una tarjeta del usuario se restauró desde la papelera</td></tr><tr><td style='padding:1px 12px 1px 0;white-space:nowrap'><b>→ Eliminada</b></td><td>una tarjeta del usuario se eliminó definitivamente tras los 30 días</td></tr></table></div>",
57
+ "usersTab_label": "Usuarios",
58
+ "usersTab_users_0_title": "ID (minúsculas)",
59
+ "usersTab_users_10_title": "→ Restaurada",
60
+ "usersTab_users_10_tooltip": "Correo cuando una tarjeta de este usuario se restaura desde la papelera",
61
+ "usersTab_users_11_title": "→ Eliminada",
62
+ "usersTab_users_11_tooltip": "Correo cuando una tarjeta de este usuario se elimina definitivamente",
63
+ "usersTab_users_1_title": "Nombre visible",
64
+ "usersTab_users_2_title": "Correo",
65
+ "usersTab_users_3_title": "→ Asignada",
66
+ "usersTab_users_3_tooltip": "Correo cuando se asigna una tarjeta a este usuario",
67
+ "usersTab_users_4_title": "→ Vence",
68
+ "usersTab_users_4_tooltip": "Correo cuando una tarjeta de este usuario vence o está atrasada",
69
+ "usersTab_users_5_title": "→ Modificada",
70
+ "usersTab_users_5_tooltip": "Correo cuando se edita una tarjeta de este usuario",
71
+ "usersTab_users_6_title": "→ Movida",
72
+ "usersTab_users_6_tooltip": "Correo cuando una tarjeta pasa a otra columna",
73
+ "usersTab_users_7_title": "→ Hecha",
74
+ "usersTab_users_7_tooltip": "Correo cuando una tarjeta se marca como hecha",
75
+ "usersTab_users_8_title": "→ Creada",
76
+ "usersTab_users_8_tooltip": "Correo cuando se crea una tarjeta nueva",
77
+ "usersTab_users_9_title": "→ Papelera",
78
+ "usersTab_users_9_tooltip": "Correo cuando una tarjeta de este usuario va a la papelera (manualmente o por la limpieza)",
79
+ "usersTab_users_label": "Usuarios",
80
+ "webhookInTab__info_text": "Los sistemas externos (scripts, agentes de IA, …) leen y escriben tarjetas mediante POST /webhook/<token>/action — comandos en el README. Cada integración debería tener su propio token.",
81
+ "webhookInTab__scopeInfo_text": "La restricción de tableros se aplica a la ruta de webhook y a la API REST: un token limitado a tableros no puede cambiar otros tableros, crear tableros ni editar usuarios. Los tokens solo se aceptan en la cabecera X-Kanban-Token o como _token en el cuerpo — ya no como parámetro de URL.",
82
+ "webhookInTab_actionStateEnabled_help": "El estado action de esta instancia ejecuta los mismos comandos que los webhooks, incluidos deleteBoard y emptyTrash, y no requiere token. Desactívelo si ningún script escribe en él.",
83
+ "webhookInTab_actionStateEnabled_label": "Aceptar comandos mediante el estado action",
84
+ "webhookInTab_corsOrigins_help": "Solo es necesario para páginas web de otro origen que llaman a la API desde el navegador, p. ej. https://dashboard.local:8123 (varias separadas por comas). Vacío = solo el mismo origen, que es el valor seguro por defecto. Los scripts, Node-RED y curl no se ven afectados.",
85
+ "webhookInTab_corsOrigins_label": "Orígenes de navegador permitidos (CORS)",
86
+ "webhookInTab_generateToken_label": "Generar token nuevo",
87
+ "webhookInTab_inboundTokens_0_title": "Nombre",
88
+ "webhookInTab_inboundTokens_1_title": "Token",
89
+ "webhookInTab_inboundTokens_2_title": "Tableros permitidos (coma o *)",
90
+ "webhookInTab_inboundTokens_3_title": "Activo",
91
+ "webhookInTab_inboundTokens_label": "Tokens",
92
+ "webhookInTab_label": "Webhooks (entrantes)",
93
+ "webhookOutTab__info_text": "En cada evento el adaptador envía un POST JSON a estas URL. Eventos: cardCreated, cardUpdated, cardMoved, cardAssigned, cardDone, cardDeleted, cardRestored, cardPurged, cardDue — o * para todos. Cada mensaje incluye dueAt (vencimiento con fecha + hora y desfase local).",
94
+ "webhookOutTab_label": "Webhooks (salientes)",
95
+ "webhookOutTab_outboundWebhooks_0_title": "Nombre",
96
+ "webhookOutTab_outboundWebhooks_1_title": "URL",
97
+ "webhookOutTab_outboundWebhooks_2_title": "Eventos (coma o *)",
98
+ "webhookOutTab_outboundWebhooks_3_title": "Activo",
99
+ "webhookOutTab_outboundWebhooks_label": "Webhooks"
100
+ }