iobroker.alias-workbench 0.9.11 → 0.10.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.
- package/README.md +106 -4
- package/admin/css/werkbank.css +50 -6
- package/admin/js/aufzaehlungen.js +24 -8
- package/admin/js/baum.js +13 -2
- package/admin/js/detail.js +310 -89
- package/admin/js/entwurf.js +443 -197
- package/admin/js/enums.js +9 -2
- package/admin/js/ergebnis.js +148 -28
- package/admin/js/erkennung.js +52 -0
- package/admin/js/mqtt.js +175 -65
- package/admin/js/musterwahl.js +103 -26
- package/admin/js/objekte.js +16 -0
- package/admin/js/pruefungen.js +10 -8
- package/admin/js/quellentausch.js +59 -12
- package/admin/js/schreiben.js +76 -43
- package/admin/js/vorlagen.js +28 -5
- package/admin/js/vorlagenblatt.js +49 -7
- package/admin/js/vorschlagen.js +60 -7
- package/admin/js/werte.js +99 -21
- package/admin/js/zielleiste.js +8 -2
- package/admin/js/zuordnung.js +79 -28
- package/admin/js/zustand.js +5 -1
- package/admin/js/zustandsliste.js +219 -42
- package/admin/sprachen/de.json +45 -18
- package/admin/sprachen/en.json +45 -18
- package/admin/tab.html +44 -44
- package/admin/vorlagen/hm-rollladen.json +3 -2
- package/admin/vorlagen/messpunkt.json +7 -2
- package/admin/vorlagen/tasmota-lampe.json +7 -2
- package/admin/vorlagen/tasmota-mehrfach.json +7 -2
- package/admin/vorlagen/tasmota-rgb.json +6 -2
- package/admin/vorlagen/tasmota-steckdose.json +7 -2
- package/io-package.json +38 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,18 @@ good is decided by things you **cannot see**:
|
|
|
25
25
|
A tool that only links datapoints helps with none of that. This adapter shows
|
|
26
26
|
all four while you are building, not hours later in the log.
|
|
27
27
|
|
|
28
|
+
### Why an admin tab, not a settings page
|
|
29
|
+
|
|
30
|
+
The workbench is an **admin tab** (`adminTab` in `io-package.json`) and runs
|
|
31
|
+
without an adapter process (`mode: none`). That is deliberate: it is an
|
|
32
|
+
interactive editor — an object tree on the left, the draft with live values on
|
|
33
|
+
the right, a dry run before anything is written, a source swap, a template
|
|
34
|
+
sheet. None of that fits into a jsonConfig page, which is built for settings.
|
|
35
|
+
The instance's actual settings do live in a normal jsonConfig page
|
|
36
|
+
(`adminUI.config: "json"`, four switches, translated into all eleven
|
|
37
|
+
languages). Without a process the adapter uses no memory while nobody has the
|
|
38
|
+
tab open.
|
|
39
|
+
|
|
28
40
|
## What it does
|
|
29
41
|
|
|
30
42
|

|
|
@@ -311,6 +323,18 @@ nothing on purpose. Fifty bare `LEVEL` channels are not a device.
|
|
|
311
323
|
When a template is rejected, the picker says why: *"1.LEVEL missing"*, not
|
|
312
324
|
*"does not fit"*. A reason you cannot act on is not a reason.
|
|
313
325
|
|
|
326
|
+
**About the role `value.power.consumption`.** Four templates (`messpunkt`,
|
|
327
|
+
`tasmota-lampe`, `tasmota-mehrfach`, `tasmota-steckdose`) give the row
|
|
328
|
+
`CONSUMPTION` the role `value.power.consumption`, which is struck through in
|
|
329
|
+
the ioBroker [state roles list](https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/stateroles.md).
|
|
330
|
+
It stays on purpose: `@iobroker/type-detector` 6.0.x recognises `CONSUMPTION`
|
|
331
|
+
only with exactly this role (`typePatterns.js`, pattern `consumption`,
|
|
332
|
+
`defaultRole: 'value.power.consumption'`). With `value.energy.consumed` the
|
|
333
|
+
point would drop out of the detected device, and vis, Alexa and the device
|
|
334
|
+
manager would no longer show any consumption. Each of the four rows carries
|
|
335
|
+
this reason in a field `_rolle`. The role will change once the type-detector
|
|
336
|
+
does.
|
|
337
|
+
|
|
314
338
|
### Role knowledge beside the rows
|
|
315
339
|
|
|
316
340
|
A template can carry `weiterePunkte`: roles for datapoints that get no row of
|
|
@@ -541,12 +565,16 @@ served as they are; editing one and reloading the tab is the whole cycle. On a
|
|
|
541
565
|
running installation the admin caches adapter files, so `iobroker upload
|
|
542
566
|
alias-workbench` after copying is what makes the browser see the change.
|
|
543
567
|
|
|
544
|
-
|
|
545
|
-
|
|
568
|
+
There are two dictionaries. `admin/i18n/` belongs to the **settings page**
|
|
569
|
+
(jsonConfig with `"i18n": true`, all eleven languages, loaded by the admin
|
|
570
|
+
itself). `admin/sprachen/` belongs to the **tab** (German and English, loaded by
|
|
571
|
+
`admin/js/sprache.js`; any other language falls back to English). A new tab
|
|
572
|
+
language is a new file in `admin/sprachen/` and an entry in `SPRACHEN` in
|
|
573
|
+
`admin/js/sprache.js` — nothing else. Watch for strings
|
|
546
574
|
written straight into `admin/tab.html`: they are replaced at runtime, and one
|
|
547
|
-
that nobody wired up stays
|
|
575
|
+
that nobody wired up stays English in every language without anyone noticing.
|
|
548
576
|
|
|
549
|
-
The tab is **
|
|
577
|
+
The tab is **30 ES modules** under `admin/js/`, loaded by the browser as
|
|
550
578
|
modules — there is no build step for them, and styling lives in one file,
|
|
551
579
|
`admin/css/werkbank.css`. Because a module boundary can be crossed wrongly in
|
|
552
580
|
ways the browser only notices while running, `npm test` checks before every
|
|
@@ -564,6 +592,80 @@ imported, and that both language files carry the same keys.
|
|
|
564
592
|
|
|
565
593
|
## Changelog
|
|
566
594
|
|
|
595
|
+
### 0.10.0 (2026-09-20)
|
|
596
|
+
**Detection and patterns**
|
|
597
|
+
* Picking another pattern re-ticks the rows and leaves them alone while the new pattern does not apply yet.
|
|
598
|
+
* Guessing gives every datapoint one slot only, and a contradicting unit rules a slot out — a start delay in seconds does not become an actual temperature.
|
|
599
|
+
* The pattern field names what is really missing, groups included (“SET / SET_HEATING / SET_COOLING”). The legend says why a pattern does not apply and offers the matching button.
|
|
600
|
+
* The hint “might fit better” only suggests patterns that apply afterwards.
|
|
601
|
+
* For “Information” the field reads “✓ 24 points” instead of “24/31 filled” — that pattern takes any number of points.
|
|
602
|
+
* The message “No remaining datapoint fits” no longer sits above the orange legend and names the rows decided by hand.
|
|
603
|
+
|
|
604
|
+
**Free slots**
|
|
605
|
+
* A slot can be created once, and every slot is listed once.
|
|
606
|
+
* “Suggest free slots” now sits in the blue box next to the pattern; the button for the whole device is called “Load all datapoints of the device” and sits above the list.
|
|
607
|
+
|
|
608
|
+
**The detail row of a point**
|
|
609
|
+
* New: “Name” and “Slot in the pattern” — the slot fills in role, type, unit and value list.
|
|
610
|
+
* “reads from” and “writes to” are wider, the formula is called “read formula” and sits below.
|
|
611
|
+
* If the slot already belongs to another row, the workbench says so instead of blaming the type. A pure measured value no longer gets a write target.
|
|
612
|
+
|
|
613
|
+
**Templates**
|
|
614
|
+
* “Apply template values” no longer deletes a value list.
|
|
615
|
+
* A template without a name can be imported and then named.
|
|
616
|
+
* A skipped row gives the reason: point missing, no JSON, or field missing.
|
|
617
|
+
* “Update template” leaves the detection as it was; an exported template can be imported again.
|
|
618
|
+
|
|
619
|
+
**Source swap**
|
|
620
|
+
* If one point fails, the note on the alias stays on the old source — the swap can be finished afterwards.
|
|
621
|
+
* The greyed-out button gives its own reason.
|
|
622
|
+
* The hint “one level up” only appears where it helps.
|
|
623
|
+
|
|
624
|
+
**Deleting and moving**
|
|
625
|
+
* The delete dialog only warns about channels that really lie below the alias.
|
|
626
|
+
* After a move the source knows its alias again right away; “to the source →” no longer jumps somewhere vague.
|
|
627
|
+
|
|
628
|
+
**Room and function**
|
|
629
|
+
* A room is found in the middle of a device name too (“Heizung_Badezimmer INT0000001”).
|
|
630
|
+
* Picking with the keyboard works like the mouse, and the offer “file it under … as well?” no longer opens a row of its own.
|
|
631
|
+
* If rooms and functions cannot be loaded, the fields say so themselves.
|
|
632
|
+
|
|
633
|
+
**Tasmota and MQTT**
|
|
634
|
+
* The IP is found on older firmware too (`tele.INFO2` in both forms).
|
|
635
|
+
* The card no longer claims a switched-off point sends; “allow sending” switches the link back on as well.
|
|
636
|
+
* Creating several send points at once yields the same objects as creating them one by one — `POWER`, `Fade` and `LedTable` as `mixed`, so the write formula takes effect.
|
|
637
|
+
* A HomeMatic actuator without a template no longer drags maintenance points along.
|
|
638
|
+
* “Ask” for SetOption59 only counts what arrived after sending; if no answer comes, “No answer …” is shown and the button stays for a re-check.
|
|
639
|
+
* The “MQTT device” card opens again on devices without a row from `tele/…`.
|
|
640
|
+
|
|
641
|
+
**Display**
|
|
642
|
+
* The number on a tree node counts what lies below it.
|
|
643
|
+
* A node without an object of its own is marked “VIR”, the device card sorts like the tree.
|
|
644
|
+
* A button reads along and stays a button; the misleading “never changes” badge is gone.
|
|
645
|
+
* JSON fields with a dot in their name can be selected.
|
|
646
|
+
|
|
647
|
+
All changes in detail, with cause and measurement: [docs/aenderungen-ausfuehrlich.md](docs/aenderungen-ausfuehrlich.md).
|
|
648
|
+
|
|
649
|
+
### 0.9.12 (2026-09-18)
|
|
650
|
+
* The small **type badges in the tree** (DEV, CHA, FOL …) now all have the same width. A node without an object of its own shows just a dot there, and its badge was narrower — its name fell out of line.
|
|
651
|
+
* **“Move …” did nothing on some aliases.** Creating alias points by hand in the admin often yields an alias without its own channel object — the node shows in the tree but is not an object itself. The workbench displayed the “Move …” button there, but clicking it opened no dialog and said nothing. Such an alias is now moved exactly like one with a channel; a missing channel is not created along the way.
|
|
652
|
+
* **No German left in the English interface.** Three places were hard-wired German: the type badge in the detail row (“Zahl”), the “Datenpunkt” field next to “writes to” and the screen-reader label of the tick boxes (“SET anlegen”). The fixed default texts in `tab.html` are now English — before, 44 German texts were only translated at runtime. The two browser-console messages are English now as well.
|
|
653
|
+
* The tab's **menu entry** now has the adapter's name in all eleven admin languages. Before, it existed in German and English only, and every other language showed “Alias Workbench”.
|
|
654
|
+
* **Why `value.power.consumption`** — four shipped templates give consumption this role, which the ioBroker roles list marks as deprecated. That is deliberate: the type-detector 6.0.x recognises consumption only with exactly this role. The reason is now written into every affected template (field `_rolle`) and into the README. The README also explains why the workbench is an admin tab rather than a settings page.
|
|
655
|
+
* **The object count in the header grew the longer the tab stayed open.** Only devices, channels, folders and states are meant to be counted — and only those are loaded. When following changes, however, the workbench took in every changed object type: after switching the system language, `system.config` sat in its store and the count read 3146 instead of 3145, likewise after every saved instance setting or adapter update. Following changes now applies the same rule as loading.
|
|
656
|
+
* **Values from another node did not update at a source.** When you select a source that already has an alias, the list also shows that alias’s rows — and they often read from somewhere else. The electricity meter shows three rows “from Solar.Netz”: import, smoothed import and house consumption. Their value was fetched once on selection and then froze; it stayed at 428 W for hours while the system reported 22 W. Only the selected node was subscribed; the rows’ sources were only added in “Edit alias” mode. The workbench now subscribes to everything it displays — including a source you point a row to by hand in the detail view. The header accordingly shows two subscriptions instead of one on the electricity meter.
|
|
657
|
+
* The legend above the list claimed **“The light pattern does not apply right now: SET requires boolean, number is set. That is why no row has a place.”** — on a device whose SET row carries `switch.light`/`boolean` and is perfectly fine. The culprit was `0_AES_KEY`: hm-rpc gives it the role `state` and the type `number`, and `state` is allowed on the light pattern’s SET place. The check asks per row “your role would fit a place, your type does not” — it never looks at who ended up holding the place, and the message then printed the PLACE instead of the row it was about. The sentence was wrong at the end too: five rows did have a place. The type reason now only applies when the named place really did stay empty; otherwise the ordinary legend is back, and every placeless row is tinted instead of just one. The case the message was built for — SET itself in the wrong type, place stays empty — is unchanged.
|
|
658
|
+
* Rows carried **“differs from the template”** where no template was in force at all — and flagged the better value while doing so. What was really compared was the raw draft, that is the bare role of the source point: on a switch actuator, after “— no template —”, `SET` showed the badge and below it “The template wants: **switch**”, while the alias holds `switch.light`, which even fits the `light` pattern. Same on `UNREACH`, where `indicator.maintenance.unreach` counted as the deviation and `indicator.unreach` as the target. And it was not only the dismissed case: on a device for which a template is **never** found, the same badge appeared. The rule now: with no template in force — dismissed or never found — no template value is recorded, so the badge, the detail line, the `←` button and the **template** filter button all drop out. Rows keep what the alias holds; that is the stock rule and has nothing to do with templates. With a template everything stays as it was — a real deviation is still shown.
|
|
659
|
+
* With **“— no template —”** the **output** picker stayed on screen if you came from the multi-output template — coming via any other template it was gone. Two routes, two answers on the same device. Worse: using the leftover picker brought the dismissed template **silently back** (measured: after switching to `Licht_Esstisch` the field read “HomeMatic switch actuator with several outputs” again). An output does not belong to the device but to the template’s `mehrfach` block — without it there is no placeholder and so nothing to choose; of 17 bundled templates exactly two carry such a block. The raw draft no longer inherits it, and the channels go through “one sub-folder per channel” instead. **And everything is ticked now.** The raw draft used to tick whatever had a place in the detected pattern; on two **identical** channels the detector picked one of them — the second — so `Licht_Esstisch` stood ticked and `Licht_Bar` empty. Which one it picks is chance, and guessing is not the job of a draft without a template: dropping the template means picking the points yourself.
|
|
660
|
+
* The expander in the template box read **“Why this template +”** and always wanted the right-hand edge. With a long name and two badges — “HomeMatic roller shutter actuator”, chosen by hand, forced — it no longer found room there and took **a line of its own**; the box grew without anything having been added. It is now a **question mark**, with the sentence in the tooltip. What was left out stays visible as a short badge (`4 WITHOUT SOURCE`) — nobody should have to go looking for the fact that points are missing — and the sentence behind it now reads “4 left out because the source is missing” instead of “Left out because the source is missing: 4”. The header no longer wraps at all: room is made by the template name, which is shortened and shown in full in its tooltip; the id stays put, because `hm-rollladen…` is no longer an id. Expanded, the question mark is filled.
|
|
661
|
+
* **A push-button is not simply any write-only point.** The workbench left the read source empty on every row whose source carried `read: false`. But HomeMatic uses that flag for two different things, counted across every device in the house: for a button press (`PRESS_SHORT` 100 points, `RAMP_STOP` 3, `STOP` 1, `OLD_LEVEL` 3 — all with `native.TYPE: ACTION`) **and** for a setting that stays put (`ON_TIME` 20 points, `RAMP_TIME` 3 — `TYPE: FLOAT`). That is why the living-room dimmer showed “never changes” on `ON_TIME` with an empty “reads from” field — on a value in seconds that one does set at the source now and then. Measured: an alias put on `1.ON_TIME`, the source set to 30 directly, and the alias showed 30. So `read: false` does not block reading. The read source is now left empty only where a button press is really meant: `native.TYPE: ACTION`, or a role starting with `button`. `OLD_LEVEL` is the case where the role is not enough — it is called `value.dimmer`.
|
|
662
|
+
* **“— no template —”** is now in the template picker. Once the workbench had detected a template it could only be swapped for another one, never dropped: the first entry of the list was a mere heading with an empty value, and the branch bailed out on an empty value. Anyone wanting to create all points of a device without a template’s defaults had no way to get there. The choice now rebuilds the draft without any template — ticked is whatever has a place in the detected pattern — and target, folder, name, room and function stay as they were.
|
|
663
|
+
* The mark on a row whose source only writes read **“reports nothing”**. That sounded like a fault — as if the device were mute. What is meant is different: the value stays where it was written and never reports back by itself. It now reads **“never changes”**, and the same in the “target does not read” check.
|
|
664
|
+
* **“One sub-folder per channel”** — the button next to “create as one device” serves a different purpose, and nothing said so: it **mirrors the folder structure of the source**. A container for the device, one channel each below it, the states below those. **The ticks now decide what appears**: one sub-folder for every channel that contributes at least one ticked row, holding exactly those rows. Before, the path built a fresh draft per channel and ticked whatever that channel’s pattern offered — things appeared that nobody had chosen (on the test device the maintenance channel got three points instead of the two ticked ones), and channels with nothing chosen were created all the same. Edits made by hand on a row — role, type, unit, formula, caption — now travel with it. **Information channels count too**: they used to be dropped, so the button said “3 of them” while six channels stood in the tree next to it — and clicking `general` on its own has long given a draft (“Information ✓ 7/14 filled”) that could be created. **The maintenance channel gets its own folder** instead of being copied into every output: `UNREACH` exists only in channel 0 of the dimmer, so that is where it belongs; whoever wants it with the light takes “create as one device”. The copying had produced nonsense — 206 raw data points of a lawn mower in each of four drafts, the three meter phases of a Shelly SHEM-3 counted as “shared” instead of as channels of their own. **Virtual channels drop out by themselves**: on a HomeMatic dimmer nothing is ticked in the two `VIRTUAL_DIMMER` channels, so nothing is created there. **States directly on the device** stay in the container, which is then created as a channel instead of a folder. **And the hint is right again**: it computed `targetFolder + channel` while writing uses `targetFolder + device + channel` — on the dishwasher it promised `alias.0.Commands` and created `alias.0.Dishwasher.Commands`, on the living-room dimmer it read `alias.0.1`, `alias.0.2`, `alias.0.3`. It now names the id, the number of ticked points and the detected type. The label says so too: “one sub-folder per channel, N of them …” instead of “one device per channel”
|
|
665
|
+
* On a **multi-output device** the draft adopted the ticks of a foreign alias. The workbench asked "is there already an alias for this device?" and answered with the one that reads **most often** from it. On Ricardo's power strip that is the consumption alias with six points from `tele.SENSOR` — it beat `RF1000` with two points from `stat.POWER1`. Output 1 then showed ELECTRIC_POWER and CONSUMPTION ticked, SET unticked, and the pattern field reported **"✕ SET missing"** on a device with a working SET. The majority rule is right for a single-output device and the wrong question for a multi-output one. The right question is: **does this alias belong to the output currently selected?** That is not guessed from names but asked of the template — which of its paths carry the placeholder? Exactly those tell the outputs apart (`stat.POWER%N%`, `cmnd.POWER%N%`); everything else (`tele.SENSOR`, `tele.LWT`) is shared. This also removes the trap from I31: `tele.INFO2` does carry a two, but no placeholder. For output 1 the bare `cmnd.POWER` counts as well — with Tasmota, POWER without a number is a second name for POWER1, measured at the device: a query to `cmnd/POWER` is answered with `{"POWER1":"ON"}`, and a topic `stat/POWER` does not exist. **The bug only hit the first glance**: coming through the tree brought the wrong stock, switching the output asked nothing at all and the template defaults won — the same output looked different depending on how you got there. All three paths now ask the same question. Single-output devices never enter the new branch by construction; without the new argument `aliasFuer` behaves line for line as before.
|
|
666
|
+
* **The target line now follows the same alias.** On a multi-output device it always showed the output number — `alias.0.Bastelzimmer.Steckdosenleiste.POWER1`, an ID that does not exist — and reported "will be created", while `RF1000` stood right next to it. Clicking would have put a second alias beside the existing ones. The source said: "the workbench cannot know what the individual output is called." That held as long as it could only ask about the device. The target line now points at `…Steckdosenleiste.RF1000` with the badge "already exists", and "update alias" hits it. Where no alias exists for the output yet — the garden valve island — the proposal from the output number stays, and so does "will be created".
|
|
667
|
+
* The **SetOption59** note appeared on every Tasmota device, including where it has no effect. It claimed an alias would show "the old value for minutes after switching" — but on the power strip not a single row reads from `tele/STATE`; they all read from `stat.POWERn`, which the device sends immediately on every command (measured: 1.07 s). "For minutes" also assumed the Tasmota default of 300 seconds; on that strip it is ten (measured: `tele/STATE` every ten seconds). The block now only appears when a row really reads from `tele/…` **and** writes to `cmnd/…`, names those rows, and reads the interval from `TelePeriod`; if it is not in the telegram the text says "on the telemetry cycle" instead of inventing a number. The same applies to the chip in the header. And the check "feedback is immediate" no longer reports "all fine" where there was nothing to check, but **"no row affected — all read from stat/…"** with a grey dot instead of a tick. Card and check ask the same function and can no longer drift apart.
|
|
668
|
+
|
|
567
669
|
### 0.9.11 (2026-09-16)
|
|
568
670
|
* After saving, the next click in the tree asked **“unsaved changes”** — about an alias that had just been written. The “something unwritten is here” mark was only ever set, never cleared; it went away solely when the draft itself was dropped, i.e. on delete and on move. It now falls after every successful write — and only then: if something went wrong, the change really is not in yet, and the question stays justified. **There is a second effect that had been missing for a long time**: while the mark stood, the workbench deliberately did not rebuild the draft. After a write the old one therefore stayed, instead of rebuilding from the freshly written alias.
|
|
569
671
|
* A second press of **“Suggest free slots”** bent back a row you had set yourself. On the air conditioner: guess nine slots, set the role of the SPEED row to `level.speed` by hand, discard — and the next suggestion put the guessed `level.mode.fan` back. The pattern slot looked free, so the same row was guessed a second time; it then carried **both** marks, “changed” and “guessed”, which exclude each other — what was just guessed cannot have been changed before. Guessing now leaves any row marked “changed” alone. The slot stays free, and the note below says why. Putting a second row next to it was the alternative — the same source point would then hold two slots, and the eighth check would rightly report it.
|
package/admin/css/werkbank.css
CHANGED
|
@@ -199,10 +199,15 @@
|
|
|
199
199
|
.tree .node.sel .chip { background:rgba(255,255,255,.22); color:var(--accent-ink); border-color:transparent; }
|
|
200
200
|
.tree .node.sel .nm { color:var(--accent-ink); }
|
|
201
201
|
.tree .node.sel > span { color:var(--accent-ink) !important; }
|
|
202
|
+
/* Feste Breite: sonst bestimmt der Text die Breite, und ein Knoten ohne
|
|
203
|
+
eigenes Objekt (nur „·“) rueckte seinen Namen aus der Flucht der
|
|
204
|
+
anderen (Ricardo, 18.09.2026). Auch DEV/CHA/FOL/STA sind so gleich
|
|
205
|
+
breit. */
|
|
202
206
|
.tree .kind {
|
|
203
207
|
font-size:8px; padding:0 4px; border-radius:4px; background:var(--surface-3);
|
|
204
208
|
color:var(--ink-3); text-transform:uppercase; letter-spacing:.04em;
|
|
205
209
|
font-family:var(--sans); font-weight:700; flex:0 0 auto;
|
|
210
|
+
width:26px; box-sizing:border-box; text-align:center;
|
|
206
211
|
}
|
|
207
212
|
.tree .idstueck { flex:0 0 auto; }
|
|
208
213
|
/* Der Name weicht zurueck: gedaempft, und er ist es, der gekuerzt wird,
|
|
@@ -840,15 +845,28 @@
|
|
|
840
845
|
/* Der Aufklapper steht in der Kopfzeile ganz rechts. `margin-left:auto`
|
|
841
846
|
schiebt ihn dorthin, ohne dass die Kopfzeile etwas davon wissen muss. */
|
|
842
847
|
.suggestbox .hd .wkopf {
|
|
843
|
-
display:inline-flex; align-items:center; gap:
|
|
844
|
-
margin-left:auto; padding:2px
|
|
848
|
+
display:inline-flex; align-items:center; gap:5px; cursor:pointer;
|
|
849
|
+
margin-left:auto; padding:2px 5px; border-radius:var(--r-sm);
|
|
845
850
|
font-size:11.5px; font-weight:400; color:var(--ink-3);
|
|
846
851
|
user-select:none; transition:background .12s, color .12s;
|
|
847
|
-
white-space:nowrap;
|
|
852
|
+
white-space:nowrap; flex:0 0 auto;
|
|
853
|
+
}
|
|
854
|
+
/* Statt „Warum diese Vorlage +" ein Fragezeichen mit Tooltip: die
|
|
855
|
+
Kopfzeile ist eng, der Satz ist lang, und gelesen wurde er ohnehin
|
|
856
|
+
nur einmal (Ricardo, 17.09.2026). Aufgeklappt wird das Zeichen
|
|
857
|
+
gefuellt - sonst saehe man dem Kopf nicht an, dass unten etwas steht. */
|
|
858
|
+
.suggestbox .hd .wkopf .fragez {
|
|
859
|
+
display:inline-flex; align-items:center; justify-content:center;
|
|
860
|
+
width:16px; height:16px; flex:0 0 auto; border-radius:50%;
|
|
861
|
+
border:1px solid var(--line-strong); color:var(--ink-2);
|
|
862
|
+
font-size:11px; font-weight:700; line-height:1;
|
|
863
|
+
}
|
|
864
|
+
.suggestbox .hd .wkopf.auf .fragez {
|
|
865
|
+
background:var(--accent); border-color:var(--accent); color:#fff;
|
|
848
866
|
}
|
|
849
|
-
.suggestbox .hd .wkopf .klappz { color:var(--ink-2); font-size:10px; }
|
|
850
867
|
.suggestbox .hd .wkopf:hover { color:var(--ink); background:var(--surface-2); }
|
|
851
|
-
.suggestbox .hd .wkopf:hover .
|
|
868
|
+
.suggestbox .hd .wkopf:hover .fragez { color:var(--accent); border-color:var(--accent); }
|
|
869
|
+
.suggestbox .hd .wkopf.auf:hover .fragez { color:#fff; }
|
|
852
870
|
.warum .wleib { margin:0; }
|
|
853
871
|
.warum .wleib ul { margin:0; padding-left:16px; }
|
|
854
872
|
.warum .wleib li { margin:1px 0; }
|
|
@@ -857,7 +875,25 @@
|
|
|
857
875
|
text-transform:uppercase; font-weight:700; color:var(--ink-3);
|
|
858
876
|
}
|
|
859
877
|
|
|
860
|
-
|
|
878
|
+
/* Die Kopfzeile bleibt EINE Zeile. Sie umbrechen zu lassen half nicht:
|
|
879
|
+
der Hinweis rechts hat `margin-left:auto`, fand bei langem Namen und
|
|
880
|
+
zwei Marken keinen Platz mehr und nahm sich eine ganze Zeile fuer
|
|
881
|
+
sich allein. Jetzt weicht stattdessen der Vorlagenname zurueck - er
|
|
882
|
+
steht vollstaendig im Tooltip und im Auswahlfeld darunter. */
|
|
883
|
+
.suggestbox .hd { display:flex; align-items:center; flex-wrap:nowrap; overflow:hidden; }
|
|
884
|
+
.suggestbox .hd > * { flex:0 0 auto; }
|
|
885
|
+
.suggestbox .hd .tname,
|
|
886
|
+
.suggestbox .hd .tid {
|
|
887
|
+
flex:0 1 auto; min-width:0; overflow:hidden;
|
|
888
|
+
text-overflow:ellipsis; white-space:nowrap;
|
|
889
|
+
}
|
|
890
|
+
.suggestbox .hd .tid {
|
|
891
|
+
font-family:var(--mono); font-size:10.5px; font-weight:400; color:var(--ink-3);
|
|
892
|
+
/* Die Kennung weicht gar nicht: sie ist kurz, und abgeschnitten sagt
|
|
893
|
+
sie nichts mehr - `hm-rollladen…` ist keine Kennung. Platz macht der
|
|
894
|
+
Name, der bis auf null zurueckgehen darf. */
|
|
895
|
+
flex-shrink:0;
|
|
896
|
+
}
|
|
861
897
|
|
|
862
898
|
.suggestbox { flex-direction:column; align-items:stretch; gap:9px; }
|
|
863
899
|
.suggestbox .hd { width:100%; }
|
|
@@ -923,6 +959,14 @@
|
|
|
923
959
|
margin:0;
|
|
924
960
|
}
|
|
925
961
|
.uebernahme .zq { color:var(--ink-2); font-size:11.5px; }
|
|
962
|
+
/* Das Raum-Angebot steht unter dem Raumfeld, in der Zeile der Marken
|
|
963
|
+
„vorgeschlagen“ — nicht in einer eigenen. Mit voller Breite fand es
|
|
964
|
+
dort keinen Platz, sobald die Funktion ihre Marke trug, und oeffnete
|
|
965
|
+
eine dritte Zeile (Ricardo, 19.09.2026: „nimmt zu viel Platz weg“).
|
|
966
|
+
Platz ist genau dann: das Angebot kommt nur nach einer Raumwahl von
|
|
967
|
+
Hand, und dann traegt der Raum keine Marke. Die Spalte der
|
|
968
|
+
Funktionsbeschriftung darunter ist frei und darf mitgenutzt werden. */
|
|
969
|
+
.zielbar .uebernahme.raumangebot { grid-row:2; grid-column:2 / 4; margin-top:-2px; }
|
|
926
970
|
.btn.mini { padding:2px 9px; font-size:11px; line-height:1.6; }
|
|
927
971
|
.btn.mini.wichtig {
|
|
928
972
|
background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600;
|
|
@@ -238,15 +238,31 @@ export function raumVorschlag(e) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
/* 4. Aus dem Geraetenamen: „HK_Bastelzimmer" -> Bastelzimmer.
|
|
242
|
-
Von hinten, weil der Raum am Ende steht, und stueckweise, weil
|
|
243
|
-
„Max_Spielzimmer" aus zwei Teilen besteht. */
|
|
241
|
+
/* 4. Aus dem Geraetenamen: „HK_Bastelzimmer" -> Bastelzimmer. */
|
|
244
242
|
var name = zusatzName(e.kanal) || (quelle ? zusatzName(quelle) : '') || '';
|
|
245
|
-
if (name) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
if (name) { return raumAusNamen(name, suche); }
|
|
244
|
+
return '';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Einen Raum im Geraetenamen finden.
|
|
248
|
+
|
|
249
|
+
Probiert wird jedes zusammenhaengende Wortstueck: laengere vor
|
|
250
|
+
kuerzeren, damit „Jonas_Schlafzimmer" vor „Schlafzimmer" gewinnt, und
|
|
251
|
+
bei gleicher Laenge das weiter hinten stehende zuerst.
|
|
252
|
+
|
|
253
|
+
Bis 19.09.2026 kamen nur Stuecke in Frage, die bis zum Ende reichen.
|
|
254
|
+
An „Heizung_Badezimmer INT0000001" hing dann immer der Anhang mit dran,
|
|
255
|
+
„Badezimmer" allein wurde nie probiert — vier Heizgruppen am
|
|
256
|
+
Testsystem und alle sieben am Produktivsystem blieben ohne Raum (Lauf
|
|
257
|
+
vom 19.09.2026, N5). Ein Raum mitten im Namen ist die Regel, nicht die
|
|
258
|
+
Ausnahme („Kueche_Licht", „Wohnzimmer_Decke_Links"); und es bleibt ein
|
|
259
|
+
Vorschlag, sichtbar markiert und vor dem Schreiben zu aendern (Ricardo,
|
|
260
|
+
19.09.2026). */
|
|
261
|
+
export function raumAusNamen(name, suche) {
|
|
262
|
+
var nt = String(name).split(/[_ .]+/).filter(function (x) { return x; });
|
|
263
|
+
for (var laenge = nt.length; laenge >= 1; laenge--) {
|
|
264
|
+
for (var start = nt.length - laenge; start >= 0; start--) {
|
|
265
|
+
var nr = suche(nt.slice(start, start + laenge).join('_'));
|
|
250
266
|
if (nr) { return nr; }
|
|
251
267
|
}
|
|
252
268
|
}
|
package/admin/js/baum.js
CHANGED
|
@@ -127,7 +127,14 @@ function baueBaum() {
|
|
|
127
127
|
|
|
128
128
|
function zaehleZustaende(k, eltern) {
|
|
129
129
|
k._eltern = eltern || null;
|
|
130
|
-
|
|
130
|
+
/* Ein `state` mit eigenen Kindern ist ein Behaelter und zaehlt sich
|
|
131
|
+
selbst nicht mit — die Zahl am Knoten nennt, was DARUNTER liegt, wie
|
|
132
|
+
rechts die Liste. Vorher stand an `0_userdata.0.Bastelzimmer` eine 7,
|
|
133
|
+
waehrend rechts „6 Zustaende" und sechs Zeilen standen (Ricardo,
|
|
134
|
+
20.09.2026; Lauf vom 19.09.2026, B1). Ein Blatt zaehlt weiter sich
|
|
135
|
+
selbst, sonst zaehlte kein Elternknoten mehr etwas. */
|
|
136
|
+
var hatKinder = Object.keys(k.kinder).length > 0;
|
|
137
|
+
var n = (k.art === 'state' && !hatKinder) ? 1 : 0;
|
|
131
138
|
var tiefe = -1;
|
|
132
139
|
Object.keys(k.kinder).forEach(function (name) {
|
|
133
140
|
var kind = k.kinder[name];
|
|
@@ -399,7 +406,11 @@ function renderKinder(knoten, filter, tiefe) {
|
|
|
399
406
|
});
|
|
400
407
|
}
|
|
401
408
|
d.appendChild(tw);
|
|
402
|
-
|
|
409
|
+
/* Ohne eigenes Objekt: „VIR“ statt eines Punkts. ioBroker selbst nennt
|
|
410
|
+
so eine Stufe `type: "virtual"` (web-Adapter, `/object` mit `depth`).
|
|
411
|
+
Gleich gestaltet wie DEV/CHA/FOL — die Reihe sieht einheitlich aus,
|
|
412
|
+
und wer es wissen will, liest es trotzdem ab (Ricardo, 19.09.2026). */
|
|
413
|
+
var kk = el('span', 'kind', k.art ? k.art.slice(0, 3) : 'vir');
|
|
403
414
|
if (!k.art) { kk.title = tr('tree.noObjectHint'); }
|
|
404
415
|
d.appendChild(kk);
|
|
405
416
|
d.appendChild(el('span', 'idstueck', k.name));
|