Einstieg Schritt 4: Erste Schritte auf dem Dashboard, Navigation in Reihenfolge des Wegs, Standort/Zweck statt OE
Kunden landen nach der Anmeldung auf dem Dashboard; der Assistent verschwindet mit dem ersten Gerät online, danach ein Hinweis auf Standorte/Zwecke, solange es nur "Neue Geräte" gibt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ecb5c9b63e
commit
e44b1b64b8
17 files changed
+120
-91
No files matched your search
@@ -448,10 +448,17 @@ def fetch_admin_konten() -> list[dict]:
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def startseite(user) -> str:
|
||||
"""Kunden landen auf dem Dashboard mit „Erste Schritte“ (Einstieg
|
||||
vereinfachen, Schritt 4), Tuxflotte-Admins wie bisher in der Flotte."""
|
||||
|
||||
return "/geraete" if user.is_superuser else "/dashboard"
|
||||
|
||||
|
||||
@router.get("/login")
|
||||
async def login_form(request: Request, user: Optional[User] = Depends(_current_user_optional)):
|
||||
if user is not None:
|
||||
return RedirectResponse("/geraete", status_code=303)
|
||||
return RedirectResponse(startseite(user), status_code=303)
|
||||
|
||||
hinweis = None
|
||||
if request.query_params.get("zurueckgesetzt"):
|
||||
@@ -493,7 +500,7 @@ async def login_submit(
|
||||
# die Sitzung muss zum gespeicherten Hash passen.
|
||||
user = await user_manager.get(user.id)
|
||||
|
||||
response = RedirectResponse("/geraete", status_code=303)
|
||||
response = RedirectResponse(startseite(user), status_code=303)
|
||||
await sitzung_setzen(response, user)
|
||||
|
||||
return response
|
||||
|
||||
@@ -81,12 +81,26 @@ def dashboard_ansicht(request: Request, user=Depends(get_current_user)):
|
||||
naechste_schritte = (dashboard or {}).get("naechste_schritte", {})
|
||||
naechste_schritte["hat_installationsmedium"] = _hat_installationsmedium(organization_id)
|
||||
|
||||
# Einstieg vereinfachen, Schritt 4: "Erste Schritte", bis das erste Gerät
|
||||
# online ist. Dazu der Workspace, den neue Geräte bekommen, und ob es ein
|
||||
# WLAN der Organisation gibt.
|
||||
erste_schritte = None
|
||||
if not naechste_schritte.get("hat_aktives_geraet"):
|
||||
wlan = anode_request("GET", f"/api/v1/organizations/{organization_id}/org-wlan")
|
||||
oes = anode_request("GET", f"/api/v1/organizations/{organization_id}/organisationseinheiten")
|
||||
standard = next((o for o in oes.get("organisationseinheiten", []) if o.get("ist_standard")), None)
|
||||
erste_schritte = {
|
||||
"org_wlan": wlan.get("org_wlan") if wlan.get("success") else None,
|
||||
"workspace": (standard or {}).get("wirksamer_workspace"),
|
||||
}
|
||||
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"dashboard.html",
|
||||
{
|
||||
"user": user,
|
||||
"naechste_schritte": naechste_schritte,
|
||||
"erste_schritte": erste_schritte,
|
||||
"ampel": (dashboard or {}).get("ampel"),
|
||||
"aktivitaeten": aktivitaeten_zusammenfassen(aktivitaeten),
|
||||
"verteilungen": (dashboard or {}).get("verteilungen"),
|
||||
|
||||
+9
-9
@@ -70,7 +70,7 @@ def oe_workspace(
|
||||
|
||||
organization_id = str(user.organization_id)
|
||||
if find_oe_in_organization(oe_id, organization_id) is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
if workspace_id:
|
||||
workspace = next((w for w in zuweisbare_workspaces(organization_id) if w["id"] == workspace_id), None)
|
||||
if workspace is None:
|
||||
@@ -111,7 +111,7 @@ def oe_umbenennen_form(request: Request, oe_id: str, user=Depends(get_current_us
|
||||
oe = find_oe_in_organization(oe_id, user.organization_id)
|
||||
|
||||
if oe is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
return templates.TemplateResponse(request, "struktur_umbenennen.html", {"user": user, "oe": oe})
|
||||
|
||||
@@ -121,7 +121,7 @@ def oe_umbenennen(oe_id: str, name: str = Form(...), user=Depends(get_current_us
|
||||
oe = find_oe_in_organization(oe_id, user.organization_id)
|
||||
|
||||
if oe is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
anode_request(
|
||||
"PATCH",
|
||||
@@ -137,7 +137,7 @@ def oe_loeschen_form(request: Request, oe_id: str, user=Depends(get_current_user
|
||||
oe = find_oe_in_organization(oe_id, user.organization_id)
|
||||
|
||||
if oe is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
return templates.TemplateResponse(request, "struktur_loeschen.html", {"user": user, "oe": oe, "fehler": None})
|
||||
|
||||
@@ -147,7 +147,7 @@ def oe_loeschen(request: Request, oe_id: str, user=Depends(get_current_user)):
|
||||
oe = find_oe_in_organization(oe_id, user.organization_id)
|
||||
|
||||
if oe is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
result = anode_request("DELETE", f"/api/v1/organisationseinheiten/{oe_id}")
|
||||
|
||||
@@ -164,7 +164,7 @@ def oe_merkmale_ansicht(request: Request, oe_id: str, user=Depends(get_current_u
|
||||
oe = find_oe_in_organization(oe_id, user.organization_id)
|
||||
|
||||
if oe is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
result = anode_request("GET", f"/api/v1/organisationseinheiten/{oe_id}/merkmale")
|
||||
merkmale = result.get("merkmale", []) if result.get("success") else []
|
||||
@@ -184,7 +184,7 @@ def oe_merkmale_ansicht(request: Request, oe_id: str, user=Depends(get_current_u
|
||||
@router.post("/struktur/{oe_id}/merkmale/{merkmal_key}/select")
|
||||
async def oe_merkmal_select(request: Request, oe_id: str, merkmal_key: str, user=Depends(get_current_user)):
|
||||
if find_oe_in_organization(oe_id, user.organization_id) is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
form = await request.form()
|
||||
optionen = parse_optionen_form(form, merkmal_key)
|
||||
@@ -200,7 +200,7 @@ async def oe_merkmal_select(request: Request, oe_id: str, merkmal_key: str, user
|
||||
@router.post("/struktur/{oe_id}/merkmale/{merkmal_key}/deselect")
|
||||
def oe_merkmal_deselect(oe_id: str, merkmal_key: str, user=Depends(get_current_user)):
|
||||
if find_oe_in_organization(oe_id, user.organization_id) is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
anode_request("POST", f"/api/v1/organisationseinheiten/{oe_id}/merkmale/{merkmal_key}/deselect")
|
||||
|
||||
@@ -210,7 +210,7 @@ def oe_merkmal_deselect(oe_id: str, merkmal_key: str, user=Depends(get_current_u
|
||||
@router.post("/struktur/{oe_id}/merkmale/{merkmal_key}/unset")
|
||||
def oe_merkmal_unset(oe_id: str, merkmal_key: str, user=Depends(get_current_user)):
|
||||
if find_oe_in_organization(oe_id, user.organization_id) is None:
|
||||
raise HTTPException(status_code=404, detail="OE wurde nicht gefunden.")
|
||||
raise HTTPException(status_code=404, detail="Standort/Zweck wurde nicht gefunden.")
|
||||
|
||||
anode_request("POST", f"/api/v1/organisationseinheiten/{oe_id}/merkmale/{merkmal_key}/unset")
|
||||
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
alle Geräte der Organisation
|
||||
</label>
|
||||
{% if ressourcen_oes or ressourcen_gruppen %}
|
||||
<small>Sonst nur auf die gewählten Organisationseinheiten (samt untergeordneten) und Gruppen:</small>
|
||||
<small>Sonst nur auf die gewählten Standorte/Zwecke (samt darunter) und Gruppen:</small>
|
||||
{% for oe in ressourcen_oes %}
|
||||
<label>
|
||||
<input type="checkbox" name="oe_ids" value="{{ oe.id }}" {% if ressource and oe.id in ressource.oes | map(attribute='id') | list %}checked{% endif %}>
|
||||
OE: {{ oe.name }}
|
||||
Standort/Zweck: {{ oe.name }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% for gruppe in ressourcen_gruppen %}
|
||||
@@ -86,7 +86,7 @@
|
||||
{% if r.ganze_organisation %}ganze Organisation
|
||||
{% elif not r.oes and not r.gruppen %}<em>nirgends (nicht verteilt)</em>
|
||||
{% else %}
|
||||
{% for oe in r.oes %}OE {{ oe.name }}<br>{% endfor %}
|
||||
{% for oe in r.oes %}{{ oe.name }}<br>{% endfor %}
|
||||
{% for g in r.gruppen %}Gruppe {{ g.name }}<br>{% endfor %}
|
||||
{% endif %}
|
||||
</small></td>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
{% else %}
|
||||
<ul>
|
||||
{% if nutzung.profile %}<li>{{ nutzung.profile | length }} Installationsprofil(e): {% for p in nutzung.profile %}{{ p.label }} <small>({{ p.organisation }})</small>{% if not loop.last %}, {% endif %}{% endfor %}</li>{% endif %}
|
||||
{% if nutzung.oes %}<li>{{ nutzung.oes | length }} OE(s): {% for o in nutzung.oes %}{{ o.name }} <small>({{ o.organisation }}, {{ "automatisch" if o.automatisch else "auf v" ~ o.version ~ " gepinnt" }})</small>{% if not loop.last %}, {% endif %}{% endfor %}</li>{% endif %}
|
||||
{% if nutzung.oes %}<li>{{ nutzung.oes | length }} Standort(e)/Zweck(e): {% for o in nutzung.oes %}{{ o.name }} <small>({{ o.organisation }}, {{ "automatisch" if o.automatisch else "auf v" ~ o.version ~ " gepinnt" }})</small>{% if not loop.last %}, {% endif %}{% endfor %}</li>{% endif %}
|
||||
<li>{{ nutzung.geraete_automatisch }} Gerät(e) übernehmen neue Versionen automatisch
|
||||
{%- for g in nutzung.geraete_gepinnt %}, {{ g.anzahl }} auf v{{ g.version }} gepinnt{% endfor %}</li>
|
||||
</ul>
|
||||
@@ -74,7 +74,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<p><small>Diese Vorlage pflegt tuxflotte. Du kannst sie unten unter „Kopieren“ als eigenen Workspace übernehmen und dann anpassen,
|
||||
oder sie unter <a href="/struktur">Organisation › Struktur</a> direkt einer OE zuweisen; dann bekommen deine Geräte die Änderungen von tuxflotte automatisch.</small></p>
|
||||
oder sie unter <a href="/struktur">Organisation › Standorte/Zwecke</a> direkt zuweisen; dann bekommen deine Geräte die Änderungen von tuxflotte automatisch.</small></p>
|
||||
{% endif %}
|
||||
|
||||
{% if not ist_entwurf %}
|
||||
|
||||
@@ -8,18 +8,18 @@
|
||||
Im fest ausgerichteten Menü klappte Firefox die Auswahlliste wieder zu,
|
||||
abgeschickt wurde dann die alte OE. #}
|
||||
<section id="oe">
|
||||
<h3>OE</h3>
|
||||
<h3>Standort/Zweck</h3>
|
||||
{% if request.query_params.get("oe_fehler") %}<p><mark>{{ request.query_params.get("oe_fehler") }}</mark></p>{% endif %}
|
||||
{% if request.query_params.get("oe_hinweis") %}<p><ins>{{ request.query_params.get("oe_hinweis") }}</ins></p>{% endif %}
|
||||
<p><small>Das Gerät bekommt Workspace und Merkmale seiner OE. Hat die neue OE einen Workspace mit anderer Distro, lehnt das Verschieben ab.</small></p>
|
||||
<p><small>Das Gerät bekommt Workspace und Einstellungen seines Standorts/Zwecks. Hat der neue einen Workspace mit einer anderen Distribution, ginge das nur mit einer Neuinstallation; dann lehnt das Verschieben ab.</small></p>
|
||||
<form method="post" action="{{ zurueck_url }}/{{ device.id }}/oe">
|
||||
<div role="group">
|
||||
<select name="oe_id" aria-label="OE auswählen">
|
||||
<select name="oe_id" aria-label="Standort/Zweck auswählen">
|
||||
{% for oe in organisationseinheiten %}
|
||||
<option value="{{ oe.id }}" {% if oe.id == device.oe_id %}selected{% endif %}>{{ oe.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="outline">In OE verschieben</button>
|
||||
<button type="submit" class="outline">Verschieben</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
@@ -161,7 +161,7 @@
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p><small>Für dieses Gerät ist „Personalisierung möglich“ nicht gesetzt (Workspace, OE oder Gruppe).</small></p>
|
||||
<p><small>Für dieses Gerät ist „Personalisierung möglich“ nicht gesetzt (Workspace, Standort/Zweck oder Gruppe).</small></p>
|
||||
{% endif %}
|
||||
|
||||
{% if personalisierungen %}
|
||||
@@ -195,7 +195,7 @@
|
||||
Einzelgerät-Ausnahmen laufen über eine Gerätegruppe mit genau diesem
|
||||
einen Gerät als Mitglied, nicht mehr über eine direkte Auswahl hier
|
||||
- so laufen alle Ausnahmen über denselben, nachvollziehbaren
|
||||
Mechanismus wie OE- und Gruppen-Einstellungen.
|
||||
Mechanismus wie Einstellungen an Standort/Zweck und Gruppen.
|
||||
</small></p>
|
||||
<form method="post" action="{{ zurueck_url }}/{{ device.id }}/eigene-gruppe">
|
||||
<button type="submit" class="outline">Eigene Gerätegruppe für dieses Gerät anlegen</button>
|
||||
@@ -219,9 +219,9 @@
|
||||
{% if eintrag.quelle and eintrag.quelle != "workspace" %}
|
||||
<br><small>
|
||||
{% if eintrag.quelle_url %}
|
||||
via <a href="{{ eintrag.quelle_url }}">{{ {"oe": "OE", "gruppe": "Gruppe"}[eintrag.quelle] }}</a>
|
||||
via <a href="{{ eintrag.quelle_url }}">{{ {"oe": "Standort/Zweck", "gruppe": "Gruppe"}[eintrag.quelle] }}</a>
|
||||
{% else %}
|
||||
via {{ {"oe": "OE", "gruppe": "Gruppe"}[eintrag.quelle] }}
|
||||
via {{ {"oe": "Standort/Zweck", "gruppe": "Gruppe"}[eintrag.quelle] }}
|
||||
{% endif %}
|
||||
</small>
|
||||
{% endif %}
|
||||
|
||||
+6
-6
@@ -69,7 +69,6 @@
|
||||
bleibt Picos zentrierendes Verhalten unveraendert richtig. */
|
||||
.primary-nav ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; align-items: stretch; gap: 0.25rem; }
|
||||
.primary-nav a { display: block; padding: 0.5rem 0.75rem; border-radius: var(--pico-border-radius); text-decoration: none; text-align: left; }
|
||||
.primary-nav a.nav-gesperrt { opacity: 0.45; }
|
||||
.primary-nav a.active { background: var(--pico-primary-background); color: var(--pico-primary-inverse); }
|
||||
.app-main { flex: 1 1 auto; min-width: 0; }
|
||||
|
||||
@@ -268,7 +267,7 @@
|
||||
else "" %}
|
||||
<header class="container">
|
||||
<nav>
|
||||
<ul><li><strong><a href="/geraete"><img src="/static/tuxflotte-logo.svg" alt="Tuxflotte" class="brand-logo">Flotten-Management</a></strong></li></ul>
|
||||
<ul><li><strong><a href="{{ '/geraete' if user and user.is_superuser else '/dashboard' }}"><img src="/static/tuxflotte-logo.svg" alt="Tuxflotte" class="brand-logo">Flotten-Management</a></strong></li></ul>
|
||||
<ul>
|
||||
<li><button id="theme-toggle" type="button" class="secondary outline" aria-label="Design umschalten">🌓</button></li>
|
||||
{% if user %}
|
||||
@@ -289,15 +288,16 @@
|
||||
<li><a href="/admin/geraete" {% if aktiver_bereich == "admin_geraete" %}class="active"{% endif %}>🖥️ Flotte</a></li>
|
||||
<li><a href="/admin/accounts" {% if aktiver_bereich == "admin_accounts" %}class="active"{% endif %}>🔑 Admin-Accounts</a></li>
|
||||
{% else %}
|
||||
{# Reihenfolge des Wegs einer neuen Organisation (Einstieg vereinfachen, Schritt 4). #}
|
||||
<li><a href="/dashboard" {% if aktiver_bereich == "dashboard" %}class="active"{% endif %}>📊 Dashboard</a></li>
|
||||
<li><a href="/installationsmedium" {% if aktiver_bereich == "installationsmedium" %}class="active"{% endif %}>💿 Installationsmedium</a></li>
|
||||
<li><a href="/geraete" {% if aktiver_bereich == "flotte" %}class="active"{% endif %}>🖥️ Flotte</a></li>
|
||||
<li><a href="/organisation" {% if aktiver_bereich == "organisation" %}class="active"{% endif %}>🏢 Organisation</a></li>
|
||||
{% if workspace_creator_frei(user.organization_id) %}
|
||||
<li><a href="/workspace" {% if aktiver_bereich == "workspace" %}class="active"{% endif %}>🧩 Workspace</a></li>
|
||||
{% else %}
|
||||
<li><a href="/workspace" class="nav-gesperrt{% if aktiver_bereich == "workspace" %} active{% endif %}" title="Dein Workspace wird derzeit von tuxflotte eingerichtet.">🧩 Workspace</a></li>
|
||||
<li><a href="/workspace" {% if aktiver_bereich == "workspace" %}class="active"{% endif %} title="Deine Geräte bekommen den Tuxflotte-Standard.">🧩 Workspace</a></li>
|
||||
{% endif %}
|
||||
<li><a href="/installationsmedium" {% if aktiver_bereich == "installationsmedium" %}class="active"{% endif %}>💿 Installationsmedium</a></li>
|
||||
<li><a href="/geraete" {% if aktiver_bereich == "flotte" %}class="active"{% endif %}>🖥️ Flotte</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -310,7 +310,7 @@
|
||||
{% if user and user.organization_id and org_ressourcen_freigeschaltet(user.organization_id) %}
|
||||
<li><a href="/organisation/ressourcen" {% if aktive_unterseite == "ressourcen" %}class="active"{% endif %}>Ressourcen</a></li>
|
||||
{% endif %}
|
||||
<li><a href="/struktur" {% if aktive_unterseite == "struktur" %}class="active"{% endif %}>Struktur</a></li>
|
||||
<li><a href="/struktur" {% if aktive_unterseite == "struktur" %}class="active"{% endif %}>Standorte/Zwecke</a></li>
|
||||
<li><a href="/gruppen" {% if aktive_unterseite == "gruppen" %}class="active"{% endif %}>Gruppen</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
+29
-19
@@ -4,31 +4,41 @@
|
||||
<h2>Dashboard</h2>
|
||||
{% import "_diagramme.html" as diagramme %}
|
||||
|
||||
<section>
|
||||
<h3>Nächste Schritte</h3>
|
||||
<ul class="dashboard-checkliste">
|
||||
<li class="{{ 'erledigt' if naechste_schritte.hat_workspace }}">
|
||||
{{ "✅" if naechste_schritte.hat_workspace else "⬜" }}
|
||||
{% if workspace_creator_frei(user.organization_id) %}
|
||||
<a href="/workspace">Workspace komponiert</a>
|
||||
{% else %}
|
||||
Workspace eingerichtet <small>(übernimmt derzeit tuxflotte für dich)</small>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% if erste_schritte %}
|
||||
{# Einstieg vereinfachen, Schritt 4: bis das erste Gerät online ist. #}
|
||||
<article id="erste-schritte">
|
||||
<h3>Erste Schritte</h3>
|
||||
<p>In drei Schritten zum ersten fertig eingerichteten Gerät.{% if erste_schritte.workspace %} Es bekommt den Tuxflotte-Standard <strong>„{{ erste_schritte.workspace.name }}“</strong>, einstellen musst du dafür nichts.{% endif %}</p>
|
||||
<ol class="dashboard-checkliste">
|
||||
<li class="{{ 'erledigt' if naechste_schritte.hat_installationsmedium }}">
|
||||
{{ "✅" if naechste_schritte.hat_installationsmedium else "⬜" }}
|
||||
<a href="/installationsmedium">Installationsmedium erstellt</a>
|
||||
<a href="/installationsmedium/erstellen">Installationsmedium erstellen</a>
|
||||
<br><small>{% if erste_schritte.org_wlan %}Die Geräte installieren über das WLAN der Organisation „{{ erste_schritte.org_wlan.ssid }}“.{% else %}Tipp vorher: Unter <a href="/organisation#wlan">Organisation</a> das WLAN der Organisation eintragen, dann bekommen es alle Geräte dauerhaft.{% endif %}</small>
|
||||
</li>
|
||||
<li class="{{ 'erledigt' if naechste_schritte.hat_geraet }}">
|
||||
{{ "✅" if naechste_schritte.hat_geraet else "⬜" }}
|
||||
<a href="/installationsmedium">Herunterladen, auf einen USB-Stick schreiben und ein Gerät davon starten</a>
|
||||
<br><small>Die Installation läuft von selbst. Alle Daten auf dem Gerät werden dabei gelöscht.</small>
|
||||
</li>
|
||||
<li class="{{ 'erledigt' if naechste_schritte.hat_aktives_geraet }}">
|
||||
{{ "✅" if naechste_schritte.hat_aktives_geraet else "⬜" }}
|
||||
<a href="/geraete">Erstes Gerät aktiv</a>
|
||||
<a href="/geraete">Das Gerät meldet sich in der Flotte</a>
|
||||
<br><small>Nach dem ersten Start richtet es sich in einigen Minuten fertig ein.</small>
|
||||
</li>
|
||||
<li class="{{ 'erledigt' if naechste_schritte.hostname_konvention_aktiv }}">
|
||||
{{ "✅" if naechste_schritte.hostname_konvention_aktiv else "⬜" }}
|
||||
Hostnamenkonvention eingerichtet <small>(optional, richtet tuxflotte auf Wunsch ein)</small>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</ol>
|
||||
</article>
|
||||
{% elif naechste_schritte.nur_standard_standort %}
|
||||
<article id="anpassen">
|
||||
<h3>Geräte anpassen</h3>
|
||||
<p><small>
|
||||
Alle Geräte bekommen bisher dasselbe. Sollen etwa der Informatikraum,
|
||||
Dienstgeräte oder Schülerleihgeräte etwas anderes bekommen, lege unter
|
||||
<a href="/struktur">Organisation › Standorte/Zwecke</a> dafür je einen
|
||||
an und verschiebe die Geräte dorthin.{% if workspace_creator_frei(user.organization_id) %}
|
||||
Mit einem eigenen <a href="/workspace">Workspace</a> bestimmst du, welche Programme sie bekommen.{% endif %}
|
||||
</small></p>
|
||||
</article>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
<h3>Flotten-Gesundheit</h3>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% if not devices %}
|
||||
<p>Keine Geräte gefunden.</p>
|
||||
{% else %}
|
||||
<input type="search" placeholder="Suche nach Hostname, Kennung, OE, Gruppe …" data-table-search="#geraete-tabelle" style="max-width: 24rem">
|
||||
<input type="search" placeholder="Suche nach Hostname, Kennung, Standort, Gruppe …" data-table-search="#geraete-tabelle" style="max-width: 24rem">
|
||||
|
||||
<figure>
|
||||
<table id="geraete-tabelle" class="kompakt">
|
||||
@@ -14,7 +14,7 @@
|
||||
<tr>
|
||||
<th data-sort data-filter>Hostname</th>
|
||||
<th data-sort data-filter>Workspace</th>
|
||||
<th data-sort data-filter>OE</th>
|
||||
<th data-sort data-filter>Standort/Zweck</th>
|
||||
<th data-sort data-filter>Gruppen</th>
|
||||
<th data-sort data-filter>Personalisiert</th>
|
||||
<th data-sort data-filter>Letzter Check-in</th>
|
||||
@@ -68,7 +68,7 @@
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>
|
||||
<a href="/geraete/{{ device.id }}#oe">In andere OE verschieben …</a>
|
||||
<a href="/geraete/{{ device.id }}#oe">Verschieben …</a>
|
||||
</li>
|
||||
<li>
|
||||
{% if gruppen %}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<section>
|
||||
<h3>Merkmale</h3>
|
||||
<p><small>Gruppen ergänzen die Grundausstattung (Workspace) der Mitgliedsgeräte. "Nicht festgelegt" überlässt die Entscheidung der OE-Kette bzw. dem Workspace-Standard des Geräts. Sagen OE-Kette und Gruppen des Geräts Widersprüchliches, gewinnt "aktiv" – eine Gruppe kann ein Merkmal also aktivieren, aber nicht gegen die OE abschalten.</small></p>
|
||||
<p><small>Gruppen ergänzen die Grundausstattung (Workspace) der Mitgliedsgeräte. „Nicht festgelegt“ überlässt die Entscheidung dem Standort/Zweck bzw. dem Workspace des Geräts. Widersprechen sich Standort/Zweck und Gruppen, gewinnt „aktiv“ – eine Gruppe kann ein Merkmal also einschalten, aber nicht gegen den Standort/Zweck abschalten.</small></p>
|
||||
{% if not kategorien %}
|
||||
<p>Keine katalogfähigen Merkmale vorhanden.</p>
|
||||
{% else %}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
{% block title %}Gruppen — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Gruppen</h2>
|
||||
<p>Querschnitts-Gruppen (z.B. Lehrer/Schulleitung) — ein Gerät kann in mehreren gleichzeitig sein. Anders als Organisationseinheiten sind Gruppen nicht verschachtelt.</p>
|
||||
<p>Querschnitts-Gruppen (z.B. Lehrer/Schulleitung) — ein Gerät kann in mehreren gleichzeitig sein. Anders als bei Standorten/Zwecken sind Gruppen nicht verschachtelt.</p>
|
||||
<p><small>
|
||||
Wofür: Gruppen eignen sich für Zuordnungen, die quer zu deiner
|
||||
Raum-/Organisationsstruktur liegen — z.B. "Schulleitung" bekommt ein
|
||||
zusätzliches Merkmal, egal in welchem Raum das Gerät gerade steht.
|
||||
Anders als bei OEs kann ein Gerät in mehreren Gruppen gleichzeitig
|
||||
sein; bei widersprüchlichen Einstellungen – auch gegenüber der OE –
|
||||
Anders als bei Standorten/Zwecken kann ein Gerät in mehreren Gruppen gleichzeitig
|
||||
sein; bei widersprüchlichen Einstellungen – auch gegenüber dem Standort/Zweck –
|
||||
gewinnt "aktiv". Eine
|
||||
Gruppe kann außerdem einen eigenen Workspace tragen — praktisch für
|
||||
eine einzelne, gezielte Ausnahme (z.B. ein einzelnes Gerät testweise
|
||||
|
||||
+15
-18
@@ -1,23 +1,20 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Struktur — Tuxflotte{% endblock %}
|
||||
{% block title %}Standorte/Zwecke — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Struktur</h2>
|
||||
<h2>Standorte/Zwecke</h2>
|
||||
{% if not meldung_oe %}
|
||||
{% if fehler %}<p><mark>{{ fehler }}</mark></p>{% endif %}
|
||||
{% if hinweis %}<p><ins>{{ hinweis }}</ins></p>{% endif %}
|
||||
{% endif %}
|
||||
<p>Organisationseinheiten (OEs) zum Verorten deiner Geräte — z.B. Gebäude oder Klassen. Ein Gerät gehört immer zu genau einer OE, neu aktivierte Geräte landen automatisch in "Neue Geräte".</p>
|
||||
<p>Wo stehen deine Geräte, oder wofür sind sie da? Zum Beispiel „Informatikraum“, „Dienstgeräte“ oder „Schülerleihgeräte“. Jedes Gerät gehört zu genau einem Standort/Zweck; neu installierte landen in „Neue Geräte“, und du kannst sie verschieben, wenn du sie austeilst.</p>
|
||||
<p><small>
|
||||
Wofür: Du kannst jeder OE eigene Merkmal-Einstellungen geben, die
|
||||
dann für alle Geräte darin gelten — spezifischere OEs überschreiben
|
||||
dabei die allgemeineren. Beispiel: "Gebäude A" → "Klasse 5a" — wenn
|
||||
du z.B. am Zeitserver von "Gebäude A" etwas änderst, gilt das für
|
||||
alle Räume darin, außer "Klasse 5a" hat selbst eine abweichende
|
||||
Einstellung dazu. Gruppen zählen gleichberechtigt mit: Sagt die OE
|
||||
oder eine Gruppe des Geräts "aktiv", ist das Merkmal aktiv — eine OE
|
||||
kann ein Merkmal, das eine Gruppe aktiviert, also nicht abschalten.
|
||||
Für Zuordnungen quer zur Ortsstruktur (z.B. "Lehrer" statt
|
||||
"Raum X") eignen sich Gruppen.
|
||||
Brauchst du am Anfang nicht: Solange alle Geräte gleich sein sollen,
|
||||
reicht „Neue Geräte“. Eigene Standorte/Zwecke lohnen sich, wenn
|
||||
Geräte etwas anderes bekommen sollen, etwa einen eigenen Workspace
|
||||
oder einzelne Einstellungen. Was du einem Standort/Zweck gibst, gilt
|
||||
auch für die darunter, außer dort ist etwas anderes festgelegt.
|
||||
Gruppen zählen gleichberechtigt mit: Schaltet der Standort/Zweck oder
|
||||
eine Gruppe des Geräts eine Einstellung ein, ist sie an.
|
||||
</small></p>
|
||||
|
||||
{% macro knoten(oe, oes) %}
|
||||
@@ -27,7 +24,7 @@
|
||||
{% elif oe.wirksamer_workspace %}<small> · Workspace: {{ oe.wirksamer_workspace.name }} (geerbt von {{ oe.wirksamer_workspace.geerbt_von }})</small>{% endif %}
|
||||
{% if oe.anzahl_geraete is defined %}<small> · {{ oe.anzahl_geraete }} Gerät(e){% if oe.distros %}: {{ oe.distros | join(", ") }}{% endif %}</small>{% endif %}
|
||||
<small>
|
||||
· <a href="/struktur/{{ oe.id }}/merkmale">Merkmale bearbeiten</a>
|
||||
· <a href="/struktur/{{ oe.id }}/merkmale">Einstellungen</a>
|
||||
{% if not oe.ist_standard %}
|
||||
· <a href="/struktur/{{ oe.id }}/umbenennen">Umbenennen</a>
|
||||
· <a href="/struktur/{{ oe.id }}/loeschen">Löschen</a>
|
||||
@@ -39,7 +36,7 @@
|
||||
<details id="oe-{{ oe.id }}-workspace"{% if hier and fehler %} open{% endif %}>
|
||||
<summary role="button" class="secondary outline">Workspace zuweisen</summary>
|
||||
{% if hier and fehler %}<p><mark>{{ fehler }}</mark></p>{% endif %}
|
||||
<p><small>Gilt für alle Geräte dieser OE und ihrer Unter-OEs, außer eine Unter-OE hat einen eigenen.
|
||||
<p><small>Gilt für alle Geräte hier und darunter, außer darunter ist ein eigener zugewiesen.
|
||||
Die Geräte müssen zur Distro des Workspace passen, sonst lehnt das Speichern mit Begründung ab.</small></p>
|
||||
<form method="post" action="/struktur/{{ oe.id }}/workspace">
|
||||
<div class="grid">
|
||||
@@ -65,7 +62,7 @@
|
||||
</details>
|
||||
{% endif %}
|
||||
<details>
|
||||
<summary role="button" class="secondary outline">Unter-OE anlegen</summary>
|
||||
<summary role="button" class="secondary outline">Darunter anlegen</summary>
|
||||
<form method="post" action="/struktur">
|
||||
<input type="hidden" name="parent_id" value="{{ oe.id }}">
|
||||
<input type="text" name="name" placeholder="Name" required>
|
||||
@@ -85,7 +82,7 @@
|
||||
|
||||
{% set wurzeln = organisationseinheiten | selectattr("parent_id", "equalto", none) | list %}
|
||||
{% if not wurzeln %}
|
||||
<p>Keine OEs gefunden.</p>
|
||||
<p>Noch keine Standorte/Zwecke.</p>
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for wurzel in wurzeln %}
|
||||
@@ -95,7 +92,7 @@
|
||||
{% endif %}
|
||||
|
||||
<details>
|
||||
<summary role="button" class="secondary outline">Neue OE auf oberster Ebene anlegen</summary>
|
||||
<summary role="button" class="secondary outline">Neuen Standort/Zweck anlegen</summary>
|
||||
<form method="post" action="/struktur">
|
||||
<input type="text" name="name" placeholder="Name" required>
|
||||
<button type="submit">Anlegen</button>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}OE löschen — Tuxflotte{% endblock %}
|
||||
{% block title %}Standort/Zweck löschen — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<p><a href="/struktur">← Struktur</a></p>
|
||||
<h2>OE löschen</h2>
|
||||
<p><a href="/struktur">← Standorte/Zwecke</a></p>
|
||||
<h2>Standort/Zweck löschen</h2>
|
||||
|
||||
{% if fehler %}
|
||||
<p><mark>{{ fehler }}</mark></p>
|
||||
{% endif %}
|
||||
|
||||
<p>Soll die OE "{{ oe.name }}" wirklich gelöscht werden?</p>
|
||||
<p>Soll „{{ oe.name }}“ wirklich gelöscht werden?</p>
|
||||
|
||||
<form method="post" action="/struktur/{{ oe.id }}/loeschen">
|
||||
<button type="submit">Ja, OE löschen</button>
|
||||
<button type="submit">Ja, löschen</button>
|
||||
<a href="/struktur" role="button" class="secondary outline">Abbrechen</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Merkmale {{ oe.name }} — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<p><a href="/struktur">← Struktur</a></p>
|
||||
<p><a href="/struktur">← Standorte/Zwecke</a></p>
|
||||
<h2>Merkmale: {{ oe.name }}</h2>
|
||||
<p>Legt fest, was Geräte in dieser OE (und ihren Unter-OEs, sofern dort nichts Spezifischeres gilt) standardmäßig bekommen. "Nicht festgelegt" überlässt die Entscheidung der nächsten Schicht (Gruppen, dann Workspace-Standard).</p>
|
||||
<p>Legt fest, was Geräte hier (und darunter, sofern dort nichts anderes gilt) standardmäßig bekommen. "Nicht festgelegt" überlässt die Entscheidung der nächsten Schicht (Gruppen, dann Workspace-Standard).</p>
|
||||
|
||||
{% if not kategorien %}
|
||||
<p>Keine katalogfähigen Merkmale vorhanden.</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}OE umbenennen — Tuxflotte{% endblock %}
|
||||
{% block title %}Standort/Zweck umbenennen — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<p><a href="/struktur">← Struktur</a></p>
|
||||
<h2>OE umbenennen</h2>
|
||||
<p><a href="/struktur">← Standorte/Zwecke</a></p>
|
||||
<h2>Standort/Zweck umbenennen</h2>
|
||||
|
||||
<form method="post" action="/struktur/{{ oe.id }}/umbenennen">
|
||||
<label for="name">Name</label>
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
{% block content %}
|
||||
<h2>Workspace</h2>
|
||||
<article>
|
||||
<p><strong>Dein Workspace wird derzeit von tuxflotte eingerichtet.</strong></p>
|
||||
<p><strong>Deine Geräte bekommen den Tuxflotte-Standard.</strong></p>
|
||||
<p>
|
||||
Die Zusammenstellung von Programmen und Einstellungen und ihre
|
||||
Zuweisung an deine Geräte übernehmen wir im Moment für dich. Wende
|
||||
dich mit Änderungswünschen bitte direkt an uns.
|
||||
Welche Programme und Einstellungen darauf sind, haben wir für dich
|
||||
zusammengestellt; du musst dafür nichts einrichten. Hast du
|
||||
Änderungswünsche, wende dich an uns. Eigene Workspaces zusammenstellen
|
||||
kannst du, sobald wir das für deine Organisation freischalten.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
{% if hinweis %}<p><ins>{{ hinweis }}</ins></p>{% endif %}
|
||||
<p><small>
|
||||
Ein Workspace legt fest, was auf deinen Geräten ist: Programme, Webapps und Einstellungen. Er läuft auf genau einer Distro.
|
||||
Auf die Geräte kommt er, indem du ihn unter <a href="/struktur">Organisation › Struktur</a> einer OE zuweist; er gilt dann für
|
||||
alle Geräte darin und in den Unter-OEs. Änderungen machst du in einem Entwurf und veröffentlichst sie als neue Version, erst dann
|
||||
Auf die Geräte kommt er, indem du ihn unter <a href="/struktur">Organisation › Standorte/Zwecke</a> zuweist; er gilt dann für
|
||||
alle Geräte dort und darunter. Änderungen machst du in einem Entwurf und veröffentlichst sie als neue Version, erst dann
|
||||
erreichen sie die Geräte.
|
||||
</small></p>
|
||||
<p><a href="/workspace/neu" role="button">+ Workspace erstellen</a></p>
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<section>
|
||||
<h3>Vorlagen von tuxflotte</h3>
|
||||
<p><small>Nur lesbar. Du kannst eine Vorlage direkt einer OE zuweisen (dann kommen Verbesserungen von tuxflotte automatisch)
|
||||
<p><small>Nur lesbar. Du kannst eine Vorlage direkt einem Standort/Zweck zuweisen (dann kommen Verbesserungen von tuxflotte automatisch)
|
||||
oder sie kopieren und die Kopie selbst anpassen.</small></p>
|
||||
{% if not vorlagen %}
|
||||
<p><small>Aktuell keine Vorlagen verfügbar.</small></p>
|
||||
|
||||
Reference in new issue
Block a user