feat(eosdash): add the profile page for battery and inverter profiles

The new Profiles page of EOSdash lists the user and packaged battery and
inverter profiles and edits them as JSON: preview without saving, save,
save as and delete, or revert a user profile to the packaged one. Saved
profiles apply at once.

One toolbar row holds the profile kind and profile selection, the Edit
button, the Share link and the status of the last action. A compact grid
summarizes the profile. A battery profile shows its charge and discharge
limit maps as heat maps as EOS evaluates them (with the exact hard
cutoffs) and its efficiency curves; an inverter profile its power at
45 degC, the DC→AC and AC→DC efficiency curves over the load fraction and
the power derating over the ambient temperature with 45 degC marked. Both
show the profile as highlighted JSON with a copy button. The sections are
collapsible and keep their state across actions.

The editor is shown only in edit mode: Edit in the toolbar opens it above
the plots, Close in the editor or Close editor in the toolbar ends it.
Edit mode is kept after preview, save and save as and across profile
changes.

Share opens a new issue with the battery or inverter profile issue form,
filled in with the profile, so users can propose their profiles for
packaging with EOS; each form asks for consent to publish the values under
Apache-2.0. EOS sends nothing itself.

Additional changes
- Add a compact variant to ConfigSection and status messages in the theme
  colors, readable in dark mode, to the EOSdash components.
- Use the muted theme color for explanatory texts.
- Check profile names before saving.
- Show the paste instruction for profiles too large for the share URL as
  text, not only as tooltip; name the selections for screen readers.
- Keep the toolbar layout when the profiles cannot be listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
Bobby Noelte
2026-11-11 22:08:18 +01:00
co-authored by Claude Opus 5.5
parent faf37abfe7
commit 3bcc902104
7 changed files with 2506 additions and 27 deletions
+43
View File
@@ -0,0 +1,43 @@
"""Tests for the shared EOSdash components."""
import pytest
from fasthtml.common import to_xml
from akkudoktoreos.server.dash.components import (
STATUS_TONES,
Error,
Info,
Success,
UpdateError,
)
class TestStatusMessages:
"""Status messages use the colors of the EOSdash theme, readable in light and dark mode."""
@pytest.mark.parametrize(
("component", "tone"),
[(Success, "success"), (Info, "info"), (Error, "error")],
)
def test_message_uses_the_theme_colors(self, component, tone):
html = to_xml(component("Saved battery profile 'x'."))
box_cls, icon_cls = STATUS_TONES[tone]
assert 'role="alert"' in html
assert "text-foreground" in html
assert box_cls in html
assert icon_cls in html
assert "Saved battery profile" in html
@pytest.mark.parametrize("component", [Success, Info, Error, UpdateError])
def test_no_daisy_alert_colors(self, component):
"""daisyUI's alert colors come from its own theme: dark text on green or gray."""
html = to_xml(component("message"))
assert "alert-success" not in html
assert "alert-info" not in html
assert "alert-error" not in html
def test_update_error_keeps_the_details(self):
html = to_xml(UpdateError("first line\nsecond line"))
assert "<details" in html
assert "first line" in html
assert STATUS_TONES["error"][0] in html