Konfigurationsbereich im Dashboard sichtbar machen
Der Abschnitt war für Benutzer unerreichbar: Er startet mit hidden, und sichtbar
gemacht hat ihn nur renderConfig() - die ausschließlich nach einem Klick auf
"anzeigen" lief, einen Knopf innerhalb des versteckten Abschnitts. Er konnte sich
also nie selbst einblenden. refresh() rief renderConfig nicht auf.
Die Sichtbarkeit entscheidet jetzt der Statuslauf, der ohnehin alle fünf Sekunden
durchläuft, anhand von trading.control_enabled.
Warum das durchgerutscht ist: Die Prüfung des Formulars lief über
getElementById("cfg-toggle").click(). Das funktioniert auch bei unsichtbaren
Elementen - die gesamte Konfigurationsoberfläche wurde damit über einen Knopf
bedient, den kein Mensch je gesehen hätte. Dieselbe Lücke wie beim vorigen
Dashboard-Fehler: Mechanik geprüft, Sichtbarkeit nicht.
Neuer Test: Für jeden <section ... hidden> wird geprüft, dass er im Statuslauf
sichtbar gemacht wird, also in refresh() oder einer der von dort gerufenen
render-Funktionen. Gegenprobe gelaufen - vor dem Fix meldet er config-section als
unerreichbar, nach dem Fix sind alle drei Abschnitte in Ordnung.
227 Tests (5 neue), ruff sauber. Im Browser ohne jeden Skriptklick geprüft: Der
Abschnitt erscheint nach dem Laden, der Knopf liegt mit 71x26 px im Dokumentfluss,
keine Blockade durch display, visibility, pointer-events oder opacity in der
Elternkette, und das Panel öffnet mit 76 Eingabefeldern.
This commit is contained in:
@@ -186,6 +186,9 @@ async function refresh() {
|
|||||||
(s.recent_trades || []).slice().reverse());
|
(s.recent_trades || []).slice().reverse());
|
||||||
renderTrading(s.trading || {});
|
renderTrading(s.trading || {});
|
||||||
renderTraining(s.training || {});
|
renderTraining(s.training || {});
|
||||||
|
// Der Abschnitt muss aus dem Statuslauf heraus sichtbar werden – sein Aufklapp-Knopf
|
||||||
|
// sitzt darin, er könnte sich sonst nie selbst einblenden.
|
||||||
|
$("config-section").hidden = !(s.trading || {}).control_enabled;
|
||||||
} catch (e) { document.getElementById("sub").textContent = "Status nicht erreichbar: " + e; }
|
} catch (e) { document.getElementById("sub").textContent = "Status nicht erreichbar: " + e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,8 +356,7 @@ function fieldRow(f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderConfig(cfg) {
|
function renderConfig(cfg) {
|
||||||
if (!cfg.available) return;
|
if (!cfg.available) { $("config-section").hidden = true; return; }
|
||||||
$("config-section").hidden = false;
|
|
||||||
cfgLoaded = cfg;
|
cfgLoaded = cfg;
|
||||||
$("cfg-meta").textContent =
|
$("cfg-meta").textContent =
|
||||||
`${cfg.config_path} · ${cfg.override_count} geänderte(s) Feld(er) in ${cfg.overrides_path}`
|
`${cfg.config_path} · ${cfg.override_count} geänderte(s) Feld(er) in ${cfg.overrides_path}`
|
||||||
|
|||||||
@@ -98,6 +98,59 @@ def test_every_referenced_element_exists():
|
|||||||
assert f'id="{element_id}"' in _DASHBOARD, f"Element #{element_id} fehlt im HTML"
|
assert f'id="{element_id}"' in _DASHBOARD, f"Element #{element_id} fehlt im HTML"
|
||||||
|
|
||||||
|
|
||||||
|
def function_body(js: str, name: str) -> str:
|
||||||
|
"""Rumpf einer Funktion per Klammerzählung ausschneiden."""
|
||||||
|
start = js.index(f"function {name}(")
|
||||||
|
open_brace = js.index("{", start)
|
||||||
|
depth = 0
|
||||||
|
for i in range(open_brace, len(js)):
|
||||||
|
depth += js[i] == "{"
|
||||||
|
depth -= js[i] == "}"
|
||||||
|
if depth == 0:
|
||||||
|
return js[open_brace : i + 1]
|
||||||
|
raise AssertionError(f"Funktion {name} ist nicht geschlossen")
|
||||||
|
|
||||||
|
|
||||||
|
def hidden_section_ids() -> list[str]:
|
||||||
|
return re.findall(r'<section id="([\w-]+)"[^>]*\shidden', _DASHBOARD)
|
||||||
|
|
||||||
|
|
||||||
|
def status_loop_code() -> str:
|
||||||
|
"""Der Code, der bei jedem Statuslauf durchläuft: refresh und die daraus gerufenen
|
||||||
|
render-Funktionen. Nur was hier steht, kann einen Abschnitt von selbst einblenden."""
|
||||||
|
js = script_body()
|
||||||
|
body = function_body(js, "refresh")
|
||||||
|
code = [body]
|
||||||
|
for name in sorted(set(re.findall(r"\b(render\w+)\(", body))):
|
||||||
|
code.append(function_body(js, name))
|
||||||
|
return "\n".join(code)
|
||||||
|
|
||||||
|
|
||||||
|
def test_there_are_hidden_sections_to_check():
|
||||||
|
assert hidden_section_ids(), "Test greift ins Leere – keine versteckten Abschnitte gefunden"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("section_id", hidden_section_ids())
|
||||||
|
def test_hidden_sections_are_unhidden_by_the_status_loop(section_id: str):
|
||||||
|
"""Ein Abschnitt, dessen Aufklapp-Knopf in ihm selbst sitzt, blendet sich sonst nie ein.
|
||||||
|
|
||||||
|
Genau das ist passiert: Der Konfigurationsbereich war für Benutzer unerreichbar, weil
|
||||||
|
nur ein Klick darin ihn sichtbar gemacht hätte. Sichtbarkeit gehört deshalb in
|
||||||
|
``refresh()``, das bei jedem Statuslauf durchläuft.
|
||||||
|
"""
|
||||||
|
code = status_loop_code()
|
||||||
|
assert f'$("{section_id}").hidden' in code, (
|
||||||
|
f"#{section_id} startet versteckt und wird im Statuslauf nicht sichtbar gemacht – "
|
||||||
|
"ein Knopf innerhalb des Abschnitts kann ihn nicht einblenden"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_functions_are_called_by_the_status_loop():
|
||||||
|
body = function_body(script_body(), "refresh")
|
||||||
|
for name in ("renderTrading", "renderTraining"):
|
||||||
|
assert f"{name}(" in body, f"{name} wird nie aufgerufen"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"needle",
|
"needle",
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user