Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bf2a3e0
style(backend): format the crate with rustfmt
gyng Jun 18, 2026
81fb556
feat: monitor input switcher, --multi dev instance, overlay auto-refi…
gyng Jun 18, 2026
b05cfda
feat(studio): palette filter + def/template previews, tab-flash + too…
gyng Jun 18, 2026
d289502
feat(ha): control widgets for fans, A/C, covers, locks, scenes, switc…
gyng Jun 18, 2026
11e475b
feat(studio): add-palette section margins, previewable trees, tab vie…
gyng Jun 18, 2026
4999d3d
feat(telemetry): order-stable history ingest by ts_ms
gyng Jun 18, 2026
0635e6b
feat(ha): history backfill so HA sparklines aren't blank on launch
gyng Jun 18, 2026
7668bb8
feat(ha): media_player widget (transport + volume)
gyng Jun 18, 2026
7912510
feat(studio): macro editor — service + entity autocomplete
gyng Jun 18, 2026
ef67ab9
feat(ha): album art for the media_player widget
gyng Jun 18, 2026
892c2ea
feat(studio): label the Button widget "Button / Macro"
gyng Jun 18, 2026
486cfba
test: v8 coverage tooling + principled 100% scope; close core-domain …
gyng Jun 18, 2026
e61eb97
test(viewTransition): cover the View Transitions helper to 100%
gyng Jun 18, 2026
354b11b
test(ha): plugin registration + catch-all action to 100%
gyng Jun 18, 2026
d174a55
style: prettier-format viewTransition.test.ts
gyng Jun 18, 2026
5a797ba
test(weather): plugin registration (0 → 80%)
gyng Jun 18, 2026
3b396e8
test(llm): ai-provider plugin registration (0 → 93%)
gyng Jun 18, 2026
c6df9ba
test(plugins): rss / agenda / mqtt registration → 100%
gyng Jun 18, 2026
b7634ab
test(weather): cover the forecast-day sensors resolver (→ 100% lines)
gyng Jun 18, 2026
fbbd9e0
fix(layout): merge-drop (wrapLeafWith) infinitely recursed in rebuild
gyng Jun 18, 2026
92c5583
test(editorOps): cover the editor ops (50 → ~85%)
gyng Jun 18, 2026
cdc3baa
test(canvas): editorOps → 100% + useEditorModel reducer 51 → ~99%
gyng Jun 18, 2026
ea287b7
test(canvas,plugins): cover canvas hooks + packages (~100% each)
gyng Jun 18, 2026
17dc353
test(settings): cover the plugin settings panels
gyng Jun 18, 2026
263d47b
test(studio): cover the studio panels + Inspector
gyng Jun 18, 2026
bf88d9a
test(meters): cover Monitor switch/editor + transcribe + preview; exc…
gyng Jun 18, 2026
94d2c37
test(meters): close the presentational-meter coverage gaps
gyng Jun 18, 2026
9051968
test(components): close the studio/widget component coverage gaps
gyng Jun 19, 2026
f9408b1
test(core): close the pure core + formula module coverage gaps
gyng Jun 19, 2026
6d6ebf0
test: close hooks/misc/plugin-logic + settings residue gaps
gyng Jun 19, 2026
4861019
test: cover the testable remainder (meters / hosts / runtime hooks / …
gyng Jun 19, 2026
f7dcd0d
test: close remaining line/function gaps toward 100%
gyng Jun 19, 2026
a721410
test(logs) + chore(coverage): finalize the coverage gate
gyng Jun 19, 2026
524ed73
fix(tests): repair the tsc type-check gate + tighten review nits
gyng Jun 19, 2026
75b1308
chore(release): bump to 0.0.48
gyng Jun 19, 2026
d99b79a
fix(e2e): mock is_dev_instance + match the reorganized palette aria-l…
gyng Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ jobs:
permissions:
checks: write

rustfmt_check:
name: Formatting for Rust backend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: rustup update stable && rustup default stable && rustup component add rustfmt
# Source-only formatting check (no compile / no frontend build needed). Run `cargo fmt` to fix.
- run: cargo fmt --all --check

client_test:
name: Tests and linting for React client
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ the working-directory-aware tools.
| Build | `cargo build` |
| Test | `cargo test` |
| Lint | `cargo clippy` |
| Format (check / fix) | `cargo fmt --check` / `cargo fmt` (default rustfmt) |
| Run full app (dev) | `cargo tauri dev` |
| Run a 2nd dev instance alongside the installed release | `cargo run -- --multi` (or `WIDGETSACK_MULTI=1`) — skips the single-instance lock + isolates config to `<app config>/multi` |
| Release build → `target/release/widgetsack.exe` | `cargo tauri build` |

> ⚠️ **Build order gotcha:** Tauri embeds `client/build` (`frontendDist`), so the frontend
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion client/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,13 @@ module.exports = {
},
settings: {
react: { version: 'detect' }
}
},
overrides: [
{
// Test code may use non-null assertions on values it has just constructed / knows are defined
// (e.g. asserting on a Patch's `monitor`). Production code keeps the strict rule.
files: ['**/*.test.ts', '**/*.test.tsx'],
rules: { '@typescript-eslint/no-non-null-assertion': 'off' }
}
]
};
1 change: 1 addition & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ build/*
/blob-report
/.playwright-mcp
/playwright/.cache
coverage/
1 change: 1 addition & 0 deletions client/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ build
/blob-report
/.playwright-mcp
/playwright/.cache
coverage/
16 changes: 14 additions & 2 deletions client/e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,24 @@ export async function previewTemplate(page: Page, name: string): Promise<void> {
await page.getByRole('button', { name, exact: true }).click();
}

/** Add a widget from the Inspector palette (Layouts section) and return the now-selected host. */
/**
* Add a widget from the Inspector palette (Layouts section) and return the now-selected host.
* `type` is the palette LABEL (e.g. "Gauge", "Analog Clock"). The palette button's accessible name
* is "<label> — <description>" (the description was folded into the aria-label), so we anchor on the
* label: the accessible name is exactly the label, or the label followed by the " — " separator. The
* anchor avoids the substring collisions a bare name match would hit (e.g. "Bar" ⊂ Gauge's
* "…linear bar…", "Text" ⊂ Transcribe's "…speech-to-text…").
*/
export async function addWidget(page: Page, type: string): Promise<Locator> {
await openSection(page, 'layouts');
// The Add palette lives in a <details> that auto-collapses once a node is selected, so re-open it
// (a no-op on a fresh boot where nothing is selected) before reaching for a palette button.
const summary = page.locator('.inspector .add-panel > summary');
if (!(await page.locator('.inspector .add-panel[open]').count())) await summary.click();
const label = type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // escape regex metachars in the label
await page
.locator('.inspector .palette')
.getByRole('button', { name: type, exact: true })
.getByRole('button', { name: new RegExp(`^${label}( — |$)`) })
.click();
const selected = page.locator('.widget.selected');
await expect(selected).toBeVisible();
Expand Down
Loading