mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 16:38:31 +00:00
v1.54.0: live robot vacuums
The plan shows the robot at work: the marker stays at its dock while a puck drives the plan, calibration is one click or a drag-and-stretch overlay, and the path is recorded server-side (current + previous run) with never/cleaning/always display modes. Also: glow is the default fill for new spaces, and the run-target search renders again.
This commit is contained in:
@@ -45,7 +45,7 @@ PLAN_ORPHAN_TTL_S = 3600
|
||||
SCHEDULED_GRACE_S = 30 * 24 * 3600
|
||||
FILES_DIR = "houseplan/files"
|
||||
CONF_ADMIN_ONLY = "admin_only"
|
||||
VERSION = "1.53.1"
|
||||
VERSION = "1.54.0"
|
||||
|
||||
DEFAULT_CONFIG: dict = {
|
||||
"spaces": [],
|
||||
|
||||
@@ -2884,4 +2884,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
||||
</button>`}
|
||||
</div>
|
||||
</div>
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.53.1 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.54.0 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
|
||||
"requirements": [],
|
||||
"single_config_entry": true,
|
||||
"version": "1.53.1"
|
||||
"version": "1.54.0"
|
||||
}
|
||||
|
||||
@@ -2884,4 +2884,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
||||
</button>`}
|
||||
</div>
|
||||
</div>
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.53.1 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.54.0 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
|
||||
Vendored
+1
-1
@@ -2884,4 +2884,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
||||
</button>`}
|
||||
</div>
|
||||
</div>
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.53.1 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
</div>`}}As.properties={_hdrH:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},As.ZOOM_MAX=8,As.ZOOM_MIN=.4,As._touchSeen=!1,As._noHoverMq="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(hover: none)").matches,As.styles=as,customElements.get("houseplan-card")||customElements.define("houseplan-card",As),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.54.0 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||
|
||||
@@ -1,5 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
## v1.54.0 — 2026-07-31
|
||||
|
||||
### Live robot vacuums
|
||||
|
||||
The plan now shows the robot while it works. The device marker stays where
|
||||
you put it — that is the dock — and a round puck drives the plan in real
|
||||
time, pouring its path out from under itself. Everything is display only:
|
||||
the card never commands the robot.
|
||||
|
||||
- **Calibration without arithmetic.** «Настроить автоматически» matches the
|
||||
robot's room list against your rooms by name and solves the transform in
|
||||
one click. When names do not match, the fit panel lays the robot's rooms
|
||||
over the plan as a dashed ghost: drag it into place, stretch it by the
|
||||
corner handles, quarter-turn and mirror with two buttons. Mirror is on by
|
||||
default — every robot map we have measured flips Y versus the screen.
|
||||
One calibration per robot map, so two floors stay independent.
|
||||
- **The path is recorded server-side.** The integration watches the robot
|
||||
itself, so the trail records with no card open, survives page reloads, and
|
||||
every screen sees the same line. The current run and one previous run are
|
||||
kept — cleaned versus not-yet-cleaned at a glance.
|
||||
- **«Показывать путь робота»**: never / while cleaning (default) / always.
|
||||
Only the last mode also draws the previous run, faded.
|
||||
- The trail never runs ahead of the icon: drawn segments lag one point and
|
||||
the growing tip is glued to the puck's animated centre every frame. It is
|
||||
drawn as a dark halo under a light core, so it stays readable over any
|
||||
room fill. The puck teleports instead of gliding when the view changes —
|
||||
zoom, floor switch or a return to the browser tab.
|
||||
- Adapters: Xiaomi Cloud Map Extractor, dreame-vacuum (Tasshack), Valetudo.
|
||||
Verified against a live Dreame X50 Master.
|
||||
|
||||
### Also
|
||||
|
||||
- **«Свет по источникам» is the default fill for new spaces** and leads the
|
||||
options list. Existing plans are untouched: a space whose owner never
|
||||
chose a fill still renders as before.
|
||||
- **Fixed: the "what to run" search showed no results.** The list is a
|
||||
scrollable box and, as a flex item, collapsed into a 1px sliver — the
|
||||
matches were there, rendered into nothing.
|
||||
|
||||
## v1.53.1 — 2026-07-30
|
||||
|
||||
- **Fix: the "what to run" search showed no results.** The results were
|
||||
|
||||
@@ -6,6 +6,45 @@
|
||||
> **Правило проекта:** оба файла пополняются в одном коммите с самим
|
||||
> изменением — как и остальная документация (см. docs/STATUS.md).
|
||||
|
||||
## v1.54.0 — 2026-07-31
|
||||
|
||||
### Роботы-пылесосы вживую
|
||||
|
||||
План теперь показывает робота за работой. Маркер устройства остаётся там,
|
||||
куда вы его поставили — это база, — а по плану в реальном времени едет
|
||||
круглая шайба, «выливая» путь из-под себя. Только отображение: карточка
|
||||
ничего роботу не командует.
|
||||
|
||||
- **Калибровка без арифметики.** «Настроить автоматически» сопоставляет
|
||||
комнаты робота с вашими по именам и решает привязку в один клик. Если
|
||||
имена не совпали, панель подгонки кладёт комнаты робота на план
|
||||
пунктирным призраком: перетащите на место, растяните за уголки, поворот
|
||||
на 90° и зеркало — двумя кнопками. Зеркало включено по умолчанию: у всех
|
||||
измеренных нами роботов ось Y перевёрнута относительно экрана. Своя
|
||||
калибровка на каждую карту робота, поэтому два этажа не мешают друг другу.
|
||||
- **Путь пишется на сервере.** Интеграция следит за роботом сама, поэтому
|
||||
след записывается даже без открытой карточки, переживает перезагрузку
|
||||
страницы, и все экраны видят одну и ту же линию. Хранятся текущая уборка
|
||||
и одна предыдущая — сразу видно, где робот уже прошёл, а где ещё нет.
|
||||
- **«Показывать путь робота»**: никогда / во время уборки (по умолчанию) /
|
||||
всегда. Прошлая уборка бледной линией рисуется только в последнем режиме.
|
||||
- След никогда не обгоняет иконку: отрисованные отрезки отстают на точку, а
|
||||
растущий кончик каждый кадр приклеен к центру едущей шайбы. Рисуется
|
||||
тёмным ореолом со светлой сердцевиной — читается на любой заливке комнат.
|
||||
При смене вида (зум, этаж, возврат на вкладку) шайба телепортируется, а
|
||||
не едет через весь план.
|
||||
- Поддержаны Xiaomi Cloud Map Extractor, dreame-vacuum (Tasshack) и
|
||||
Valetudo. Проверено на живом Dreame X50 Master.
|
||||
|
||||
### Кроме того
|
||||
|
||||
- **«Свет по источникам» — режим по умолчанию для новых пространств** и
|
||||
первый в списке. Существующие планы не трогаем: пространство, где режим
|
||||
не выбирали, выглядит как раньше.
|
||||
- **Исправлено: поиск «что запускать» не показывал результатов.** Список —
|
||||
прокручиваемый блок, и как flex-элемент он схлопывался в полоску 1px:
|
||||
совпадения были, но отрисовывались в ничто.
|
||||
|
||||
## v1.53.1 — 2026-07-30
|
||||
|
||||
- **Фикс: поиск «что запускать» не показывал результатов.** Результаты были —
|
||||
|
||||
+2
-2
@@ -15,12 +15,12 @@
|
||||
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| Version | **v1.53.1** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
|
||||
| Version | **v1.54.0** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
|
||||
| Workflow | Since 2026-07-22: minor changes go to branch **`dev`** (build + smokes → deploy home → commit → push, NO release); releases are batched on the owner's command (merge dev→main, one tag, one release with a summary changelog, CI checked on dev beforehand) |
|
||||
| GitHub | https://github.com/Matysh/houseplan-card — **`main` carries every published release, the latest tag is the current version above**; `dev` is where work lands and is merged into `main` at release time (so `dev` is normally equal to or ahead of `main`, never behind). Push via SSH key `ha_jb` (remote git@github.com:…); API releases via the fine-grained PAT in `~/.git-credentials` (Contents R/W, issued 2026-07-23) |
|
||||
| CI | validate.yml (hacs + hassfest + frontend + backend) green; release.yml attaches the bundle on release publish |
|
||||
| HACS | Custom repository works. **Inclusion PR: hacs/default#9004** — open, valid, labeled, mergeable clean, never drafted. Queue: 1212 open, 835 older than ours. Merge rate COLLAPSED: 75 in July but almost all in the first decade, 0 in the last week (checked 2026-07-29) — maintainers process in rare bursts; ETA unknowable, months at best. Nothing actionable on our side |
|
||||
| Home instance | ha.jbstudio.pro (SSH port **22222**, key `ha_jb`; HA config root is `/mnt/data/supervisor/homeassistant` — `/config` does NOT exist in this SSH environment), deployed **v1.53.1** via direct copy (HACS custom repo also installed) |
|
||||
| Home instance | ha.jbstudio.pro (SSH port **22222**, key `ha_jb`; HA config root is `/mnt/data/supervisor/homeassistant` — `/config` does NOT exist in this SSH environment), deployed **v1.54.0** via direct copy (HACS custom repo also installed) |
|
||||
| Localization | UI en/ru (src/i18n/*.json), everything user-visible localized incl. kiosk popover |
|
||||
| Tests | Four layers: frontend unit (`npm test`, node:test over `test-build/`), pure backend (`pytest tests_backend`, runs anywhere), HA-harness backend (same folder, CI only — needs py3.13 + pytest-homeassistant-custom-component), and browser smokes (`demo/smoke_*.mjs`, headless chromium). **Counts are not written down here** — they went stale within two releases while the version line beside them was kept current, which reads as less coverage than exists (review R5-2). Run `npm run inventory` for the current numbers, or read them off the last CI run |
|
||||
| Vacuums | Live robot vacuums shipped (docs/VACUUM.md): puck, server-side trails with display modes, fit-panel calibration. Verified on a live Dreame X50 Master |
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "houseplan-card",
|
||||
"version": "1.53.1",
|
||||
"version": "1.54.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "houseplan-card",
|
||||
"version": "1.53.1",
|
||||
"version": "1.54.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lit": "^3.1.3",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "houseplan-card",
|
||||
"version": "1.53.1",
|
||||
"version": "1.54.0",
|
||||
"description": "Interactive house plan Lovelace card for Home Assistant",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -42,7 +42,7 @@ import { cardStyles } from './styles';
|
||||
import { fitInSquare, contentBounds, spaceModels } from './space-geometry';
|
||||
import { langOf, t, type I18nKey } from './i18n';
|
||||
|
||||
const CARD_VERSION = '1.53.1';
|
||||
const CARD_VERSION = '1.54.0';
|
||||
const LS_KEY = 'houseplan_card_layout_v1';
|
||||
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
|
||||
const LS_ZOOM = 'houseplan_card_zoom_v1';
|
||||
|
||||
Reference in New Issue
Block a user