Setup: Erwartungswert je Listenposition, gruen auch dort (2026.9.1.15)
Tuer- und Fenstersensoren haben vier Positionen, aber nur einen Beispielnamen (front_left_door). Der beschreibt die erste; die anderen drei koennen ihn nie enthalten. Folge: nur die erste Position konnte gruen werden, und im Kopf stand ein Erwartungswert, der fuer drei von vier Zeilen nicht galt. Neu "beispiele" je Position im Feld-Katalog und feldBeispiel(feld, idx) im Panel. Der Erwartungswert steht jetzt an jeder Position statt im Kopf - rechtsbuendig, in der kleinen grauen Schrift des Positionslabels. Auch die Sortierung der Vorschlagsliste nutzt ihn, sonst stuende in allen vier Zeilen dieselbe Entitaet oben. Typografie: .setup-feld-hinweis ist fuer die Kopfzeile gebaut (14px, --fg, rechtsbuendig, max-width 55%). Im 12,5px-Positionslabel wirkt das falsch herum. Eine Regel im Kontext .setup-unterfeld-label .setup-feld-hinweis laesst Groesse und Farbe erben; die Rechtsbuendigkeit kommt aus justify-content: space-between am Label, wie eine Ebene darueber bei .setup-feld-kopf. Verifiziert: alle acht Positionen tragen ihren eigenen Beispielnamen, py_compile und Panel als Modul sauber, audi_ha_test ohne Fehler gestartet. Die Darstellung selbst habe ich nicht im Browser gesehen - das Panel liess sich in der Testinstanz nicht ansteuern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# AGENTS.md — Project state, review findings, open items, and working rules
|
# AGENTS.md — Project state, review findings, open items, and working rules
|
||||||
|
|
||||||
**Last updated: 2026-09-01** (Rueckblick ohne Nullfahrten, Streckenwahl gemeinsam in `verlauf.py`,
|
**Last updated: 2026-09-01** (Setup: gruene Bestaetigung und Erwartungswert je Listenposition,
|
||||||
|
`2026.9.1.15`, Abschnitt BG. Davor: Rueckblick ohne Nullfahrten, Streckenwahl gemeinsam in `verlauf.py`,
|
||||||
`2026.9.1.14`, Abschnitt BF. Davor: Fahrtstrecke auf 100 m: CAN als Anker, GNSS als Nachkommastelle,
|
`2026.9.1.14`, Abschnitt BF. Davor: Fahrtstrecke auf 100 m: CAN als Anker, GNSS als Nachkommastelle,
|
||||||
`2026.9.1.10`, Abschnitt BE. Davor: Nachlauf-Abzug nur mit zugeordnetem `TRIP_SENSOR`, `2026.9.1.9`;
|
`2026.9.1.10`, Abschnitt BE. Davor: Nachlauf-Abzug nur mit zugeordnetem `TRIP_SENSOR`, `2026.9.1.9`;
|
||||||
davor „502" beim Neustart entschärft, OTA-Bündel auf `2026.9.1.8`
|
davor „502" beim Neustart entschärft, OTA-Bündel auf `2026.9.1.8`
|
||||||
@@ -6879,6 +6880,45 @@ weglaesst.
|
|||||||
innerhalb einer einzigen langen `trip_status`-Phase. Nachweisbar bleibt es an den 13 Faellen; live
|
innerhalb einer einzigen langen `trip_status`-Phase. Nachweisbar bleibt es an den 13 Faellen; live
|
||||||
zeigt es sich bei der naechsten kurzen Fahrt.
|
zeigt es sich bei der naechsten kurzen Fahrt.
|
||||||
|
|
||||||
|
## BG. Setup: gruene Bestaetigung, Erwartungswert je Position (2026.9.1.11–.15)
|
||||||
|
|
||||||
|
Zwei Wuensche des Eigentuemers vom 01.09.2026, die zusammengehoeren.
|
||||||
|
|
||||||
|
### Gruen, wenn die Zuordnung zum Beispielnamen passt
|
||||||
|
|
||||||
|
Enthaelt die zugeordnete Entitaet den Beispielnamen der Rolle, faerbt sich das Feld leicht gruen.
|
||||||
|
Dieselbe Pruefung, die `entitaetScore()` ohnehin mit 8 gewichtet - hier nur fuers Auge, damit man
|
||||||
|
eine richtig belegte Rolle sieht, ohne den langen Entity-Namen Zeichen fuer Zeichen mit dem Beispiel
|
||||||
|
daneben zu vergleichen.
|
||||||
|
|
||||||
|
Bewusst **nur ein Hinweis, keine Bedingung**: Installationen mit anderer Datenquelle haben andere
|
||||||
|
Namen und sind trotzdem richtig zugeordnet. Deshalb gruen als Bestaetigung, aber kein Rot und keine
|
||||||
|
Warnung, wenn es fehlt. Und nicht waehrend gesucht wird - dann steht die Sucheingabe im Feld, nicht
|
||||||
|
die Zuordnung. Die Farbe kommt per `color-mix` aus dem vorhandenen `--ok`-Ton und dem Feldgrund
|
||||||
|
statt aus einem eigenen Gruen, damit sie in beiden Themen ruhig bleibt.
|
||||||
|
|
||||||
|
`„Auf Standard zuruecksetzen"` ist im selben Zug entfallen - Knopf, Symbol, Zuhoerer, CSS und der
|
||||||
|
nur dafuer vorhandene Helfer `setupStandardwert()`.
|
||||||
|
|
||||||
|
### Listenfelder brauchen vier Beispiele, nicht eines
|
||||||
|
|
||||||
|
Tuer- und Fenstersensoren haben vier Positionen, aber nur **einen** Beispielnamen
|
||||||
|
(`front_left_door`). Der beschreibt die erste; die anderen drei koennen ihn nie enthalten. Folge:
|
||||||
|
nur die erste Position konnte gruen werden, und im Kopf stand ein Erwartungswert, der fuer drei von
|
||||||
|
vier Zeilen nicht galt.
|
||||||
|
|
||||||
|
Neu: `"beispiele"` je Position im Feld-Katalog, `feldBeispiel(feld, idx)` im Panel. Der
|
||||||
|
Erwartungswert steht jetzt **an jeder Position** statt im Kopf - rechtsbuendig, in der kleinen grauen
|
||||||
|
Schrift des Positionslabels. Auch die Sortierung der Vorschlagsliste nutzt ihn, sonst stuende in
|
||||||
|
allen vier Zeilen dieselbe Entitaet oben.
|
||||||
|
|
||||||
|
**Merkposten zur Typografie:** `.setup-feld-hinweis` ist fuer die Kopfzeile gebaut (14px, `--fg`,
|
||||||
|
rechtsbuendig, `max-width: 55%`). Im 12,5px-Positionslabel wirkt das falsch herum - groesser und
|
||||||
|
dunkler als die Zeile, in der es steht. Eine eigene Regel im Kontext
|
||||||
|
`.setup-unterfeld-label .setup-feld-hinweis` laesst es Groesse und Farbe erben; die Rechtsbuendigkeit
|
||||||
|
kommt aus `justify-content: space-between` am Label, wie eine Ebene darueber bei
|
||||||
|
`.setup-feld-kopf`.
|
||||||
|
|
||||||
## Working conventions (observed — keep them)
|
## Working conventions (observed — keep them)
|
||||||
|
|
||||||
- German is the project language: identifiers, comments, commits, UI texts. Exceptions:
|
- German is the project language: identifiers, comments, commits, UI texts. Exceptions:
|
||||||
|
|||||||
@@ -293,11 +293,26 @@ FELDER: list[dict] = [
|
|||||||
"hinweis": "\"aus\"/off = zu. Für \"Sicher abgestellt\" wichtig.",
|
"hinweis": "\"aus\"/off = zu. Für \"Sicher abgestellt\" wichtig.",
|
||||||
"domains": ["binary_sensor"], "device_classes": ["door"], "units": [], "liste": True, "positionen": POSITIONEN,
|
"domains": ["binary_sensor"], "device_classes": ["door"], "units": [], "liste": True, "positionen": POSITIONEN,
|
||||||
"pflicht": False, "beispiel": "front_left_door",
|
"pflicht": False, "beispiel": "front_left_door",
|
||||||
|
# Ein Beispielname je Position. "beispiel" allein beschreibt nur die
|
||||||
|
# erste; die anderen drei koennen "front_left_door" nie enthalten und
|
||||||
|
# standen deshalb ohne Erwartungswert da.
|
||||||
|
"beispiele": [
|
||||||
|
"front_left_door",
|
||||||
|
"front_right_door",
|
||||||
|
"rear_left_door",
|
||||||
|
"rear_right_door",
|
||||||
|
],
|
||||||
"stichworte": ["tür", "door"]},
|
"stichworte": ["tür", "door"]},
|
||||||
{"key": "FENSTER_SENSOREN", "label": "Fenster", "gruppe": "sicherheit",
|
{"key": "FENSTER_SENSOREN", "label": "Fenster", "gruppe": "sicherheit",
|
||||||
"hinweis": "\"aus\"/off = zu.",
|
"hinweis": "\"aus\"/off = zu.",
|
||||||
"domains": ["binary_sensor"], "device_classes": ["window"], "units": [], "liste": True, "positionen": POSITIONEN,
|
"domains": ["binary_sensor"], "device_classes": ["window"], "units": [], "liste": True, "positionen": POSITIONEN,
|
||||||
"pflicht": False, "beispiel": "front_left_window",
|
"pflicht": False, "beispiel": "front_left_window",
|
||||||
|
"beispiele": [
|
||||||
|
"front_left_window",
|
||||||
|
"front_right_window",
|
||||||
|
"rear_left_window",
|
||||||
|
"rear_right_window",
|
||||||
|
],
|
||||||
"stichworte": ["fenster", "window"]},
|
"stichworte": ["fenster", "window"]},
|
||||||
{"key": "HECKKLAPPE_SENSOR", "label": "Heckklappe", "gruppe": "sicherheit",
|
{"key": "HECKKLAPPE_SENSOR", "label": "Heckklappe", "gruppe": "sicherheit",
|
||||||
"hinweis": "\"aus\"/off = zu.",
|
"hinweis": "\"aus\"/off = zu.",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":"2026.9.1.14","sha256":"f1fa3a91435bfc80f3f4245e52c488e3487fe12e5031349e1d7d20ca757d4b7d","bytes":265727,"gebaut":"2026-09-01T16:47:50Z"}
|
{"version":"2026.9.1.15","sha256":"c7eda6e1a85b2d4295b0bd21383b66895dfb217a5a788a6ccf92acee467cad4c","bytes":265741,"gebaut":"2026-09-01T16:59:16Z"}
|
||||||
Binary file not shown.
@@ -3044,7 +3044,7 @@ function entitaetName(id) {
|
|||||||
Domain/Einheit/Device-Class sind Zusatzpunkte fürs Sortieren, wenn der
|
Domain/Einheit/Device-Class sind Zusatzpunkte fürs Sortieren, wenn der
|
||||||
Schalter "Nur passende Sensoren" aus ist (dann filtern sie nicht hart,
|
Schalter "Nur passende Sensoren" aus ist (dann filtern sie nicht hart,
|
||||||
siehe entitaetKandidaten()). */
|
siehe entitaetKandidaten()). */
|
||||||
function entitaetScore(feld, e, suchtext) {
|
function entitaetScore(feld, e, suchtext, idx) {
|
||||||
let score = 0;
|
let score = 0;
|
||||||
const hay = (e.id + " " + e.name).toLowerCase();
|
const hay = (e.id + " " + e.name).toLowerCase();
|
||||||
for (const wort of feld.stichworte || []) if (hay.includes(wort)) score += 5;
|
for (const wort of feld.stichworte || []) if (hay.includes(wort)) score += 5;
|
||||||
@@ -3054,12 +3054,15 @@ function entitaetScore(feld, e, suchtext) {
|
|||||||
// Der Signalname aus dem Katalog ("z. B. can_fuel_volume") ist der
|
// Der Signalname aus dem Katalog ("z. B. can_fuel_volume") ist der
|
||||||
// treffsicherste Hinweis, den es gibt - deutlich mehr wert als ein
|
// treffsicherste Hinweis, den es gibt - deutlich mehr wert als ein
|
||||||
// einzelnes Stichwort.
|
// einzelnes Stichwort.
|
||||||
if (feld.beispiel && hay.includes(feld.beispiel.toLowerCase())) score += 8;
|
// Bei Listenfeldern der Name der jeweiligen Position, nicht der der ersten -
|
||||||
|
// sonst stuende in allen vier Zeilen dieselbe Entitaet oben.
|
||||||
|
const beispiel = feldBeispiel(feld, idx);
|
||||||
|
if (beispiel && hay.includes(beispiel.toLowerCase())) score += 8;
|
||||||
if (suchtext && hay.includes(suchtext.trim().toLowerCase())) score += 10;
|
if (suchtext && hay.includes(suchtext.trim().toLowerCase())) score += 10;
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
function entitaetKandidaten(feldKey, suchtext, aktuellerWert) {
|
function entitaetKandidaten(feldKey, suchtext, aktuellerWert, idx) {
|
||||||
const feld = setupKatalog().find((f) => f.key === feldKey);
|
const feld = setupKatalog().find((f) => f.key === feldKey);
|
||||||
if (!feld) return [];
|
if (!feld) return [];
|
||||||
const text = (suchtext || "").trim().toLowerCase();
|
const text = (suchtext || "").trim().toLowerCase();
|
||||||
@@ -3101,7 +3104,7 @@ function entitaetKandidaten(feldKey, suchtext, aktuellerWert) {
|
|||||||
);
|
);
|
||||||
if (genau.length) liste = genau;
|
if (genau.length) liste = genau;
|
||||||
}
|
}
|
||||||
liste.sort((a, b) => entitaetScore(feld, b, suchtext) - entitaetScore(feld, a, suchtext));
|
liste.sort((a, b) => entitaetScore(feld, b, suchtext, idx) - entitaetScore(feld, a, suchtext, idx));
|
||||||
return liste.slice(0, 60);
|
return liste.slice(0, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3192,11 +3195,34 @@ function setupSchliessen() {
|
|||||||
anderer Datenquelle, deren Namen nicht passen und die trotzdem richtig
|
anderer Datenquelle, deren Namen nicht passen und die trotzdem richtig
|
||||||
zugeordnet sind. Deshalb grün als Bestätigung, aber kein Rot und keine
|
zugeordnet sind. Deshalb grün als Bestätigung, aber kein Rot und keine
|
||||||
Warnung, wenn es fehlt. */
|
Warnung, wenn es fehlt. */
|
||||||
function entitaetPasstZumBeispiel(key, wert) {
|
function entitaetPasstZumBeispiel(key, idx, wert) {
|
||||||
if (!wert) return false;
|
if (!wert) return false;
|
||||||
const feld = setupKatalog().find((f) => f.key === key);
|
const beispiel = feldBeispiel(setupKatalog().find((f) => f.key === key), idx);
|
||||||
if (!feld || !feld.beispiel) return false;
|
if (!beispiel) return false;
|
||||||
return String(wert).toLowerCase().includes(String(feld.beispiel).toLowerCase());
|
return String(wert).toLowerCase().includes(String(beispiel).toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Der Beispielname für eine bestimmte Position einer Rolle.
|
||||||
|
|
||||||
|
Listenfelder (Tür- und Fenstersensoren, vier Positionen) haben je Position
|
||||||
|
einen eigenen Namen: die zweite Position kann "front_left_door" nie
|
||||||
|
enthalten. Ohne diese Unterscheidung stand nur bei der ersten Position ein
|
||||||
|
Erwartungswert, und nur sie konnte grün werden - vom Eigentümer beanstandet
|
||||||
|
am 01.09.2026. */
|
||||||
|
function feldBeispiel(feld, idx) {
|
||||||
|
if (!feld) return null;
|
||||||
|
if (idx != null && Array.isArray(feld.beispiele) && feld.beispiele[idx]) {
|
||||||
|
return feld.beispiele[idx];
|
||||||
|
}
|
||||||
|
return feld.beispiel || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Der Klammertext "(z. B. …)" - im Kopf einer Rolle wie an einer
|
||||||
|
Listenposition derselbe Bau, damit beide gleich aussehen. */
|
||||||
|
function beispielHinweis(name) {
|
||||||
|
return name
|
||||||
|
? `<span class="setup-feld-hinweis">(z. B. <span class="setup-feld-einheit">${esc(name)}</span>)</span>`
|
||||||
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entity-IDs, die im Arbeitsstand mehr als einer Rolle zugeordnet sind. */
|
/* Entity-IDs, die im Arbeitsstand mehr als einer Rolle zugeordnet sind. */
|
||||||
@@ -4513,7 +4539,11 @@ function feldEinheitAnzeige(feld) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function entitaetZeilenMarkup(feldId, key, suchtext, aktuellerWert) {
|
function entitaetZeilenMarkup(feldId, key, suchtext, aktuellerWert) {
|
||||||
const kandidaten = entitaetKandidaten(key, suchtext, aktuellerWert);
|
// Die Position steckt in der Feld-Kennung ("KEY:idx") - sie entscheidet,
|
||||||
|
// welcher Beispielname die Vorschlagsliste anfuehrt.
|
||||||
|
const teile = String(feldId).split(":");
|
||||||
|
const idx = teile.length === 2 ? Number(teile[1]) : null;
|
||||||
|
const kandidaten = entitaetKandidaten(key, suchtext, aktuellerWert, idx);
|
||||||
if (!kandidaten.length) return `<div class="entitaet-leer">Keine passende Entität gefunden</div>`;
|
if (!kandidaten.length) return `<div class="entitaet-leer">Keine passende Entität gefunden</div>`;
|
||||||
return kandidaten.map((e) => {
|
return kandidaten.map((e) => {
|
||||||
const zustand = HASS.states[e.id] ? HASS.states[e.id].state : null;
|
const zustand = HASS.states[e.id] ? HASS.states[e.id].state : null;
|
||||||
@@ -4536,7 +4566,7 @@ function entitaetCombo(key, idx) {
|
|||||||
// Waehrend gesucht wird nicht gruen faerben - der Text im Feld ist dann
|
// Waehrend gesucht wird nicht gruen faerben - der Text im Feld ist dann
|
||||||
// die Sucheingabe und nicht die Zuordnung, die Faerbung wuerde ihm
|
// die Sucheingabe und nicht die Zuordnung, die Faerbung wuerde ihm
|
||||||
// widersprechen.
|
// widersprechen.
|
||||||
const treffer = !offen && entitaetPasstZumBeispiel(key, wert);
|
const treffer = !offen && entitaetPasstZumBeispiel(key, idx, wert);
|
||||||
return `<div class="entitaet-combo">
|
return `<div class="entitaet-combo">
|
||||||
<span class="entitaet-combo-icon">${LUPE_SVG}</span>
|
<span class="entitaet-combo-icon">${LUPE_SVG}</span>
|
||||||
<input type="text" class="entitaet-combo-input${treffer ? " passend" : ""}" autocomplete="off" spellcheck="false"
|
<input type="text" class="entitaet-combo-input${treffer ? " passend" : ""}" autocomplete="off" spellcheck="false"
|
||||||
@@ -4570,12 +4600,13 @@ function setupFeldzeile(feld) {
|
|||||||
|
|
||||||
Listenfelder bekommen es ebenfalls: dort ist der Name der ersten
|
Listenfelder bekommen es ebenfalls: dort ist der Name der ersten
|
||||||
Position das Muster, nach dem sich die anderen drei richten. */
|
Position das Muster, nach dem sich die anderen drei richten. */
|
||||||
const erwartet = feld.beispiel || "";
|
// Bei Listenfeldern steht das Beispiel NICHT im Kopf, sondern an jeder
|
||||||
|
// Position - siehe unten. Ein einzelner Name im Kopf beschriebe nur die
|
||||||
|
// erste der vier und liesse die anderen drei ohne Erwartungswert dastehen.
|
||||||
|
const erwartet = feld.liste ? "" : feld.beispiel || "";
|
||||||
// Der Klammertext in Label-Größe/-Farbe, der Sensorname darin in derselben
|
// Der Klammertext in Label-Größe/-Farbe, der Sensorname darin in derselben
|
||||||
// kleinen/grauen Schrift wie die Einheit ("[on/off]").
|
// kleinen/grauen Schrift wie die Einheit ("[on/off]").
|
||||||
const hinweis = erwartet
|
const hinweis = beispielHinweis(erwartet);
|
||||||
? `<span class="setup-feld-hinweis">(z. B. <span class="setup-feld-einheit">${esc(erwartet)}</span>)</span>`
|
|
||||||
: "";
|
|
||||||
const kopf = `<div class="setup-feld-kopf">
|
const kopf = `<div class="setup-feld-kopf">
|
||||||
<span class="setup-feld-label">${esc(feld.label)}${einheit ? ` <span class="setup-feld-einheit">[${esc(einheit)}]</span>` : ""}</span>
|
<span class="setup-feld-label">${esc(feld.label)}${einheit ? ` <span class="setup-feld-einheit">[${esc(einheit)}]</span>` : ""}</span>
|
||||||
${hinweis}
|
${hinweis}
|
||||||
@@ -4585,7 +4616,7 @@ function setupFeldzeile(feld) {
|
|||||||
<div class="setup-unterfelder">
|
<div class="setup-unterfelder">
|
||||||
${feld.positionen.map((pos, i) => `
|
${feld.positionen.map((pos, i) => `
|
||||||
<div class="setup-unterfeld">
|
<div class="setup-unterfeld">
|
||||||
<span class="setup-unterfeld-label">${esc(pos)}</span>
|
<span class="setup-unterfeld-label">${esc(pos)}${beispielHinweis(feldBeispiel(feld, i))}</span>
|
||||||
${entitaetCombo(feld.key, i)}
|
${entitaetCombo(feld.key, i)}
|
||||||
${entitaetStatusWarnung((setupZuordnung[feld.key] || [])[i])}
|
${entitaetStatusWarnung((setupZuordnung[feld.key] || [])[i])}
|
||||||
</div>`).join("")}
|
</div>`).join("")}
|
||||||
|
|||||||
@@ -1378,7 +1378,17 @@ img.carfix.klein { aspect-ratio: auto; height: auto; }
|
|||||||
}
|
}
|
||||||
.setup-unterfelder { display: flex; flex-direction: column; gap: 12px; }
|
.setup-unterfelder { display: flex; flex-direction: column; gap: 12px; }
|
||||||
.setup-unterfeld { display: flex; flex-direction: column; gap: 4px; }
|
.setup-unterfeld { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.setup-unterfeld-label { font-size: 12.5px; color: var(--fg3); }
|
/* Positionsname links, Erwartungswert rechts - derselbe Bau wie
|
||||||
|
.setup-feld-kopf eine Ebene darueber, damit beide Zeilen dieselbe Kante
|
||||||
|
haben. Der Hinweis erbt hier die kleine graue Schrift des Labels; die
|
||||||
|
14px/--fg-Form von .setup-feld-hinweis passt nur in die Kopfzeile. */
|
||||||
|
.setup-unterfeld-label {
|
||||||
|
font-size: 12.5px; color: var(--fg3);
|
||||||
|
display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
|
||||||
|
}
|
||||||
|
.setup-unterfeld-label .setup-feld-hinweis {
|
||||||
|
font-size: inherit; color: inherit; max-width: none; flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.entitaet-combo { position: relative; }
|
.entitaet-combo { position: relative; }
|
||||||
.entitaet-combo-icon {
|
.entitaet-combo-icon {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"domain": "audi_dashboard",
|
"domain": "audi_dashboard",
|
||||||
"name": "Audi Dashboard",
|
"name": "Audi Dashboard",
|
||||||
"version": "2026.9.1.14",
|
"version": "2026.9.1.15",
|
||||||
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
|
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
|
||||||
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
|
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
|
||||||
"codeowners": ["@paul"],
|
"codeowners": ["@paul"],
|
||||||
|
|||||||
Reference in New Issue
Block a user