Skip to content

Commit 87cb170

Browse files
committed
release: 1.33.0
1 parent bdb52a1 commit 87cb170

86 files changed

Lines changed: 3105 additions & 1270 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@ Anything not listed here yet is on `main` and ships with the next release.
66

77
## Unreleased
88

9+
## 1.33.0
10+
11+
- Value and Stat are one widget now, with a Style setting. Stored stat tiles keep their look and
12+
everything they had set.
13+
- Six new looks for it: sparkline, split, bar, segment, pill and hero.
14+
- Every value tile can now take a trend arrow, colour stops, a caption, a badge and a second
15+
reading. Those were stat-only before.
16+
- And every stat tile can take per-state icons, which were value-only.
17+
- The Settings page reads a lot shorter. Every explanation on it was rewritten to say the same thing
18+
in a line or two.
19+
- The Widget gallery section is gone. Its five widgets are example templates, so they now sit in
20+
Custom widgets as a "Start from an example" row, which is where a copy of one ends up anyway.
21+
- A widget you have not picked an item for yet says so, instead of drawing a slider at 0 or a dial
22+
at empty as though the device were off.
23+
- A long item name no longer spills out of a small tile on the "not on this server" message.
24+
- The palette has a search box. It also matches what a widget does, so "graph" finds the chart.
25+
- Dialogs use the height of the screen on a desktop, so fewer widgets sit below the fold.
26+
- The dashboard generator shows both layout choices without scrolling. One of them was hidden under
27+
the buttons on a laptop, and both were on a phone.
28+
- A stepper shows the value the item actually holds. An item at 3.6 read "4" when the step was 1.
29+
- An upload that fails because the file is the wrong kind no longer tells you to sign in.
30+
- "No matching icons" no longer renders one icon wide.
31+
- The HABPanel report says where a dashboard's web address comes from. It said names became
32+
addresses, when they come from HABPanel's own dashboard ids.
33+
934
## 1.32.0
1035

1136
- A timeline widget with nothing to draw covered the whole dashboard with an invisible box and

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
A dashboard UI for [openHAB](https://www.openhab.org/). Touch-friendly dashboards for phones,
99
tablets and wall panels, built and configured entirely in the browser. No file editing.
1010

11-
**Status:** in daily use, latest release **1.32.0**. A community project, not an official openHAB UI.
11+
**Status:** in daily use, latest release **1.33.0**. A community project, not an official openHAB UI.
1212

1313
## Requirements
1414

@@ -59,9 +59,9 @@ to show for it. Open tabs offer to reload themselves.
5959
## Widgets
6060

6161
Buttons and switches, sliders, dials, steppers, colour pickers, selections, rollershutters,
62-
thermostats and media players. Value and stat readouts, compasses, batteries, clocks, weather and
63-
plain labels. Charts, timelines, floor plans with live light glows, cameras, images, embedded
64-
pages and the server log.
62+
thermostats and media players. One value readout drawn eight ways (plain, stat, sparkline, split,
63+
bar, segment, pill and hero), plus compasses, batteries, clocks, weather and plain labels. Charts,
64+
timelines, floor plans with live light glows, cameras, images, embedded pages and the server log.
6565
Anything missing can be built as a custom widget from an HTML template, with an optional sandboxed
6666
JavaScript API.
6767

‎docs/getting-started.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ and it is where everything else in this page happens.
3434

3535
In edit mode:
3636

37-
1. Press **+** to open the palette and pick a widget. A Button is the one to start with.
37+
1. Press **+** to open the palette and pick a widget, or type in its search box. A Button is the
38+
one to start with.
3839
2. It lands on the grid. Drag it about, drag a corner to resize.
3940
3. Tap it to open its settings.
4041

@@ -93,4 +94,4 @@ the whole configuration back.
9394
- **Settings › Kiosk & wall panel** is for a screen on a wall: no chrome, no menu, and the screen
9495
kept awake.
9596
- **Settings › Custom widgets** is where you write your own tile out of HTML when no built-in one
96-
fits.
97+
fits. Five examples ship with it, and starting from one is usually quicker than a blank page.

‎docs/theming.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ colours or all 27.
4040

4141
| Token | What it paints |
4242
|---|---|
43-
| `good` | A reading that moved the way you want (a stat tile's trend arrow) |
43+
| `good` | A reading that moved the way you want (the value widget's trend arrow) |
4444
| `bad` | A reading that moved the wrong way |
4545
| `accent-ink` | Text drawn **on** the accent: filled tiles, chips, badges |
4646

@@ -117,8 +117,9 @@ adopting it.
117117
| `.nh-fader__*` | The slider widget's four other styles (gradient, wedge, inset rail, bubble), which keep their own look in every theme on purpose. `.nh-fader__read` is the reading, `__bound` the ends of an inset scale, `__track` and `__fill` the two painted layers |
118118
| `.nh-log`, `.nh-log__line`, `.nh-log__level` | The log widget's console. The root carries `--lg-warn`, the one colour the tokens do not have (errors use `bad`); `.nh-log__line--warn` and `--error` mark the lines that carry it, `__time`, `__logger` and `__msg` are the columns, and `.nh-log__jump` is the pill that takes the reader back to the newest line |
119119
| `.nh-switch__track`, `.nh-switch__thumb` | The sliding toggle, which is the button widget drawn in its switch style. `.nh-switch--on` marks the on state, and `.nh-switch__state` is the ON/OFF caption under it |
120-
| `.nh-value__text`, `.nh-value__unit` | A reading and its unit, set separately |
121-
| `.nh-stat__value`, `.nh-stat__caption`, `.nh-stat__badge` | The stat tile |
120+
| `.nh-value__text`, `.nh-value__unit` | A reading and its unit in the value widget's plain style, set separately |
121+
| `.nh-stat__value`, `.nh-stat__frac`, `.nh-stat__unit`, `.nh-stat__caption`, `.nh-stat__badge` | The reading, its tenths, its unit, the small line under it and the marker beside it. The value widget's other seven styles all draw through these, so one rule reaches every one of them. `.nh-stat` is the stat style's own column, with `--center` and `--right` for its alignment |
122+
| `.nh-read`, `.nh-read__main` | The root of the six styles added after plain and stat, with `.nh-read--spark` through `--hero` saying which is drawn. `__plot`, `__line` and `__area` are the sparkline, `__track` and `__fill` the bar, `__disc` the split's icon circle, `__pill` the pill. Sizing the reading itself belongs on `.nh-stat__value` above, not here |
122123
| `.nh-clock__time`, `.nh-clock__date` | The clock |
123124
| `.nh-chart__chip`, `.nh-chart__legend` | Chart chrome |
124125
| `.nh-gauge__*`, `.nh-dial__*` | Gauge and dial internals |

‎e2e/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ id (`kitchen` becomes `kitchen-2`), which is one of the things that suite checks
162162
Four more deliberate exceptions, each for the same reason: the feature under test decides the id,
163163
so the suite cannot invent one.
164164

165-
- `e2e-gallery.mjs` installs gallery widgets, which land under the catalogue's own ids
165+
- `e2e-gallery.mjs` adds the bundled example widgets, which land under the catalogue's own ids
166166
(`widgetdef:gallery-*`). It deletes exactly that prefix, before and after.
167167
- `e2e-partial.mjs` imports partial exports, which can create a numbered copy
168168
(`dashboard:nh-e2e-pdash-2`). It deletes its own prefixes, and because importing legitimately

‎e2e/e2e-assembly.mjs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ try {
112112
toggle: true, command: switchState,
113113
}),
114114
w('b3', 'button', 6, 2, 2, 1, {
115-
label: 'Zone C', command: 'noop', icon: 'mdi:factory', caption: 'Vision line',
115+
item: ITEMS.switch, label: 'Zone C', command: 'noop', icon: 'mdi:factory', caption: 'Vision line',
116116
imageUrl:
117117
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23123f24'/%3E%3C/svg%3E",
118118
}),
@@ -121,8 +121,8 @@ try {
121121
toggle: true, command: 'never-match',
122122
}),
123123
w('l1', 'label', 0, 2, 2, 1, { text: 'Bare Label' }),
124-
w('s1', 'stat', 2, 2, 2, 1, { item: ITEMS.dimmer, label: 'Stat', icon: 'mdi:factory', group: 'Panel' }),
125-
w('s2', 'stat', 4, 2, 2, 1, { item: ITEMS.dimmer, label: 'Stat 2', group: 'Panel' }),
124+
w('s1', 'value', 2, 2, 2, 1, { style: 'stat', item: ITEMS.dimmer, label: 'Stat', icon: 'mdi:factory', group: 'Panel' }),
125+
w('s2', 'value', 4, 2, 2, 1, { style: 'stat', item: ITEMS.dimmer, label: 'Stat 2', group: 'Panel' }),
126126
],
127127
},
128128
}),

‎e2e/e2e-audit2.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Audit fixes for configuration that did not come from the editor.
22
import { launchChromium } from './lib/browser.mjs'
3-
import { BASE, NS, TOKEN, AUTH } from './lib/target.mjs'
3+
import { BASE, NS, TOKEN, AUTH, ITEMS } from './lib/target.mjs'
44

55
const launchBrowser = async () => { for (const c of ['msedge', 'chrome']) { try { return await launchChromium({ channel: c, headless: true }) } catch {} } return launchChromium({ headless: true }) }
66

@@ -45,7 +45,7 @@ await put({
4545
version: 1, id: 'nh-e2e-a2', name: 'E2E Audit2', columns: 12, rowHeight: 'match', gap: 5,
4646
widgets: [
4747
{ id: 'a2-label', type: 'label', config: { text: 'Scaled', fontSize: 40 }, layout: { lg: { x: 0, y: 0, w: 3, h: 2 } } },
48-
{ id: 'a2-btn', type: 'button', config: { label: 'Pick', command: 'ON' }, layout: { lg: { x: 3, y: 0, w: 2, h: 2 } } },
48+
{ id: 'a2-btn', type: 'button', config: { item: ITEMS.switch, label: 'Pick', command: 'ON' }, layout: { lg: { x: 3, y: 0, w: 2, h: 2 } } },
4949
],
5050
},
5151
})

‎e2e/e2e-button.mjs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ const ACCENT = '#e0459a'
1717
const DIM = 'nh_e2e_btn'
1818
const STR = 'nh_e2e_btnstr'
1919
const HOLD_MS = 800 // comfortably past the 500ms threshold
20+
// The legacy dashboard below carries no version field at all, which reads as 1, and a save has to
21+
// land it on today's. Named so the next schema bump is a visible one-line edit rather than a check
22+
// that quietly starts asserting the wrong number - SCHEMA_VERSIONS.dashboard in
23+
// web/src/model/schema.ts is the source of truth.
24+
const LEGACY_SCHEMA = 1
25+
const CURRENT_SCHEMA = 3
2026

2127
const results = []
2228
const ok = (name, cond, detail = '') => {
@@ -673,7 +679,11 @@ try {
673679
const widgets = stored?.config?.widgets ?? []
674680
const old = widgets.find((w) => w.id === 'w-old')
675681
const oldBare = widgets.find((w) => w.id === 'w-oldbare')
676-
ok('saving writes the dashboard back at the current version', Number(stored?.config?.version) === 2, 'version=' + stored?.config?.version)
682+
ok(
683+
'saving writes the dashboard back at the current version',
684+
Number(stored?.config?.version) === CURRENT_SCHEMA && CURRENT_SCHEMA > LEGACY_SCHEMA,
685+
`version=${stored?.config?.version}, seeded at ${LEGACY_SCHEMA}, current is ${CURRENT_SCHEMA}`
686+
)
677687
ok('the switch is stored as a button in switch style', old?.type === 'button' && old?.config?.style === 'switch', JSON.stringify(old?.type))
678688
ok(
679689
'with the behaviours it used to imply written out beside it',

‎e2e/e2e-editfix.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ try {
8181
{ id: 'w-b', type: 'clock', config: { showDate: false }, layout: { lg: { x: 3, y: 0, w: 2, h: 2 } } },
8282
{ id: 'w-c', type: 'label', config: { text: 'C' }, layout: { lg: { x: 0, y: 4, w: 2, h: 1 } } },
8383
{ id: 'w-d', type: 'label', config: { text: 'D' }, layout: { lg: { x: 0, y: 5, w: 2, h: 1 } } },
84-
{ id: 'w-e', type: 'button', config: { label: 'Nav', command: 'ON' }, layout: { lg: { x: 6, y: 0, w: 2, h: 2 } } },
84+
{ id: 'w-e', type: 'button', config: { item: ITEMS.switch, label: 'Nav', command: 'ON' }, layout: { lg: { x: 6, y: 0, w: 2, h: 2 } } },
8585
{ id: 'w-f', type: 'dial', config: { item: ITEMS.temperature, label: 'Tenths', min: 0, max: 200, step: 0.1, readOnly: true }, layout: { lg: { x: 6, y: 3, w: 3, h: 3 } } },
8686
{ id: 'w-g', type: 'dial', config: { item: ITEMS.temperature, label: 'Whole', min: 0, max: 200, step: 1, readOnly: true }, layout: { lg: { x: 9, y: 3, w: 3, h: 3 } } },
8787
],

‎e2e/e2e-ember.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ try {
161161
ok('rose letters only when asked', (await pa.locator('.nh-compass__rose').count()) === 8)
162162
const customFill = await pa.locator('.nh-gcell:has(.nh-compass__rose) .nh-compass__cardinal').getAttribute('fill', { timeout: 4000 }).catch(() => null)
163163
ok('explicit color reaches the cardinal (attribute, not class)', customFill === '#00ff88', customFill ?? 'none')
164-
const emptyText = await pa.locator('.nh-compass__empty').textContent().catch(() => '')
165-
ok('unconfigured compass explains itself', emptyText === 'No item configured', emptyText)
164+
const emptyText = await pa.locator('.nh-widget__unset').first().innerText().catch(() => '')
165+
ok('unconfigured compass explains itself', /pick one in this widget/i.test(emptyText), emptyText.replace(/\s+/g, ' '))
166166

167167
if (FORMATTED_ITEM) {
168168
const fmtState = await (await fetch(itemUrl(FORMATTED_ITEM), { headers: AUTH })).json()

0 commit comments

Comments
 (0)