mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 13:48:57 +00:00
fix(card): static «Show as LED strip» in the device dialog; demo icons (#780)
The full Validate on a6c4001c found two things:
- smoke_help_affordance: the device dialog shifted when the LED tool chunk
arrived after it opened (the representation section appeared late). A
device without a strip now gets the static section at once (label in the
base dictionary); the press loads the tool, leaves the dialog through its
own guard and starts drawing for the same marker. A strip's device still
loads the tool with the dialog. The dialog alone no longer loads anything.
- smoke_lazy_admin_locale counted nine namespace chunks (stale since the
`tools` namespace); it now reads NAMESPACE_LOCALE_CHUNKS and accepts the
editor's own `tools-de`.
- demo/srv/assets/icons.js regenerated: the demo/golden ha-icon stub lacked
mdi:led-strip-variant and mdi:link-variant(-off).
Issue: #780
User-Visible: no
This commit is contained in:
@@ -9,10 +9,13 @@
|
||||
// отказ — английский в строках пространства, один тост, без вечной загрузки.
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { launchColdView, checkAll, finish } from './serve.mjs';
|
||||
import { NAMESPACE_LOCALE_CHUNKS } from '../scripts/bundle-manifest.mjs';
|
||||
|
||||
const manifest = JSON.parse(readFileSync('dist/houseplan-assets.json', 'utf8'));
|
||||
const NAMESPACE_CHUNKS = (manifest.lazyNamespaceLocaleFiles || []).map((path) => path.split('/').at(-1));
|
||||
if (NAMESPACE_CHUNKS.length !== 9) throw new Error('bundle manifest has no nine namespace locale chunks');
|
||||
// Every namespace × ru/de/fr is its own chunk (#627; `tools` #780 stage 3, `led` #780).
|
||||
if (NAMESPACE_CHUNKS.length !== NAMESPACE_LOCALE_CHUNKS.length)
|
||||
throw new Error(`bundle manifest has ${NAMESPACE_CHUNKS.length} namespace locale chunks, expected ${NAMESPACE_LOCALE_CHUNKS.length}`);
|
||||
const chunkName = (namespace, language) => {
|
||||
const name = NAMESPACE_CHUNKS.find((candidate) => candidate.startsWith(`${namespace}-${language}-`));
|
||||
if (!name) throw new Error(`namespace chunk ${namespace}-${language} is absent from the manifest`);
|
||||
@@ -178,7 +181,7 @@ const out = {};
|
||||
out.settingsRequestsEachGermanNamespaceOnce = namespaces
|
||||
.every((namespace) => count(requested, chunkName(namespace, 'de')) === 1);
|
||||
out.settingsRequestsNoOtherLanguage = namespaceRequests(requested)
|
||||
.every((name) => /^(settings|support|topology)-de-/.test(name));
|
||||
.every((name) => /^(settings|support|topology|tools)-de-/.test(name));
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* and computes no field with `light_pools: false`.
|
||||
*/
|
||||
import { launch, check, finish } from './serve.mjs';
|
||||
import { installHpTestOnPage } from './helpers/hp-test.mjs';
|
||||
|
||||
const { page, browser } = await launch({ width: 1000, height: 820 }, 1);
|
||||
const ledRequests = [];
|
||||
@@ -132,4 +133,26 @@ const staticCards = await evaluate(async () => {
|
||||
check('static card without light_pools: passive stripe, no field', JSON.stringify(staticCards.plain), JSON.stringify({ stripe: true, field: false, hit: false }));
|
||||
check('static card with light_pools: the field', JSON.stringify(staticCards.pools), JSON.stringify({ stripe: true, field: true, hit: false }));
|
||||
|
||||
// The device dialog offers «Show as LED strip» before the tool is loaded:
|
||||
// a static section (no dialog shift), the press loads the tool and starts
|
||||
// drawing for this same marker after the dialog's own close path.
|
||||
// A fresh page without strips: entering the Devices editor alone loads nothing.
|
||||
await page.reload();
|
||||
await page.waitForFunction(() => window.__card?._loadOk);
|
||||
await installHpTestOnPage(page);
|
||||
ledRequests.length = 0;
|
||||
const before = 0;
|
||||
await evaluate(async () => { await window.__hpTest.setMode('devices'); await window.__hpTest.openMarkerDialog('d_tv'); });
|
||||
await page.waitForTimeout(200);
|
||||
check('static «Show as LED strip» without the tool chunk', await evaluate(() =>
|
||||
!!window.__card.shadowRoot.querySelector('[data-led-representation="icon"] [data-led-action="show-strip"]')),
|
||||
true);
|
||||
check('the dialog alone loads no LED tool', ledRequests.filter((name) => name.startsWith('led-strip-editor-')).length, before);
|
||||
await page.click('[data-led-representation] [data-led-action="show-strip"]');
|
||||
await page.waitForTimeout(600);
|
||||
check('the press loads the tool and draws for the same marker', await evaluate(() => {
|
||||
const led = window.__card._ledEditor;
|
||||
return !!led?.tool && led.chain?.convert === 'd_tv' && !window.__card._markerDialog;
|
||||
}));
|
||||
|
||||
await finish(browser);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -609,6 +609,7 @@
|
||||
"title.add_device": "Gerät zum Plan hinzufügen",
|
||||
"devbar.add": "Hinzufügen",
|
||||
"devbar.led": "LED-Streifen",
|
||||
"devbar.led_show": "Als LED-Streifen zeigen",
|
||||
"devbar.rules": "Symbolregeln",
|
||||
"device_inbox.button": "Geräte",
|
||||
"device_inbox.title": "Geräte auf dem Plan",
|
||||
|
||||
@@ -609,6 +609,7 @@
|
||||
"title.add_device": "Add a device to the plan",
|
||||
"devbar.add": "Add",
|
||||
"devbar.led": "LED strip",
|
||||
"devbar.led_show": "Show as LED strip",
|
||||
"devbar.rules": "Icon rules",
|
||||
"device_inbox.button": "Devices",
|
||||
"device_inbox.title": "Devices on the plan",
|
||||
|
||||
@@ -609,6 +609,7 @@
|
||||
"title.add_device": "Ajouter un appareil au plan",
|
||||
"devbar.add": "Ajouter",
|
||||
"devbar.led": "Ruban LED",
|
||||
"devbar.led_show": "Afficher en ruban LED",
|
||||
"devbar.rules": "Règles d’icônes",
|
||||
"device_inbox.button": "Appareils",
|
||||
"device_inbox.title": "Appareils sur le plan",
|
||||
|
||||
@@ -609,6 +609,7 @@
|
||||
"title.add_device": "Добавить устройство на план",
|
||||
"devbar.add": "Добавить",
|
||||
"devbar.led": "LED-лента",
|
||||
"devbar.led_show": "Показывать LED-лентой",
|
||||
"devbar.rules": "Правила иконок",
|
||||
"device_inbox.button": "Устройства",
|
||||
"device_inbox.title": "Устройства на плане",
|
||||
|
||||
+19
-6
@@ -41,15 +41,28 @@ export function ledButton(card: LedCardPort): TemplateResult {
|
||||
|
||||
/**
|
||||
* The device dialog's "icon ↔ LED strip" section — in the Devices editor
|
||||
* only (ТЗ §5). A strip's dialog elsewhere still loads the tool: its save
|
||||
* renames the link on a rebinding.
|
||||
* only (ТЗ §5). A device without a strip gets the static «Show as LED strip»
|
||||
* at once (the tool loads on the press, the dialog does not shift); a strip's
|
||||
* device loads the tool, also outside Devices: its save renames the link on a
|
||||
* rebinding.
|
||||
*/
|
||||
export function ledSection(card: LedCardPort, devId: string): TemplateResult | typeof nothing {
|
||||
const devices = card._mode === 'devices';
|
||||
if (!devices && !card._serverCfg?.spaces.some((space: { led_strips?: Array<{ marker: string | null }> }) =>
|
||||
space.led_strips?.some((strip) => strip.marker === devId))) return nothing;
|
||||
const led = ledEditorFor(card, 'dialog');
|
||||
return devices ? led?.markerSection(devId) ?? nothing : nothing;
|
||||
const owned = !!card._serverCfg?.spaces.some((space: { led_strips?: Array<{ marker: string | null }> }) =>
|
||||
space.led_strips?.some((strip) => strip.marker === devId));
|
||||
if (!devices) {
|
||||
if (owned) ledEditorFor(card, 'dialog');
|
||||
return nothing;
|
||||
}
|
||||
if (card._ledEditor) return card._ledEditor.markerSection(devId);
|
||||
if (owned) { ledEditorFor(card, 'dialog'); return nothing; }
|
||||
return html`<div class="hpf-group led-representation" data-led-representation="icon">
|
||||
<div class="row" style="flex-wrap:wrap;gap:6px"><button class="btn ghost" type="button" data-led-action="show-strip"
|
||||
@click=${() => {
|
||||
const entry = `tool${Date.now()}`, go = () => ledEditorFor(card, entry)?.convertFromDialog(devId);
|
||||
if (ledEditorModule(entry, go)) go();
|
||||
}}><ha-icon icon="mdi:led-strip-variant"></ha-icon>${card._t('devbar.led_show')}</button></div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const hasStrips = (config: ServerConfig | null | undefined) => !!config?.spaces.some(
|
||||
|
||||
@@ -808,6 +808,11 @@ export class LedStripEditor {
|
||||
return !this.host._markerDialog;
|
||||
}
|
||||
|
||||
/** «Show as LED strip» pressed before the tool was loaded: same guard, then draw. */
|
||||
async convertFromDialog(devId: string): Promise<void> {
|
||||
if (await this.leaveDialog()) this.open(devId);
|
||||
}
|
||||
|
||||
private crossings = new WeakMap<object, { n: number; spaces: string[] }>();
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user