Dagsplan: tredje visning ved siden av tavle/tabell. To-kolonne planlegger der man plukker oppgaver fra backlog og bygger en ordnet plan for dagen (drag-sortering, kapasitet i timer, datovelger). Per bruker, per dato, lagret i plans.json; synkes mellom egne faner via plan-WS-melding. Kommentar ved statusbytte: når en oppgave markeres ferdig/blokkert (knapp, kanban-drag eller modal) tilbys en valgfri kommentar som festes til oppgaven (kind:status) og legges i aktivitetsloggen — atomisk i ett update-kall. 20 integrasjonstester (8 nye), alle grønne. README + CLAUDE.md oppdatert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
317 lines
12 KiB
HTML
317 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="no">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>NetOps To-Do · Network Engineer</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
|
||
<header>
|
||
<div>
|
||
<h1><span id="conn-dot" title="Tilkoblingsstatus"></span> NetOps To-Do</h1>
|
||
<div class="sub" id="conn-text">kobler til …</div>
|
||
</div>
|
||
<div class="header-actions">
|
||
<span class="online-row" id="online-row" title="Pålogget nå"></span>
|
||
<span class="user-chip" id="user-chip" title="Pålogget bruker">…</span>
|
||
<button id="activityBtn" title="Aktivitetslogg (a)">☰ Aktivitet</button>
|
||
<button id="exportBtn" title="Eksporter JSON">⬇</button>
|
||
<button id="importBtn" title="Importer JSON (erstatter alt)">⬆</button>
|
||
<input type="file" id="importFile" accept=".json" style="display:none">
|
||
<button class="primary" id="newTaskBtn" title="Ny oppgave (n)">+ Ny oppgave</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="anon-banner" id="anon-banner">
|
||
<span>Du er pålogget som <b>anon</b>. Velg et navn så kollegene ser hvem som gjør hva.</span>
|
||
<button class="primary" id="setNameBtn">Sett navn</button>
|
||
</div>
|
||
|
||
<div class="quickadd">
|
||
<div class="quickadd-row">
|
||
<input type="text" id="quickadd-input" autocomplete="off"
|
||
placeholder='Hurtig-registrering: f.eks. "Bytt SFP i core-sw01 #l1 p2 @me !imorgen ~1h loc:DC-OSL-1"'>
|
||
<button class="primary" id="quickadd-btn">Legg til</button>
|
||
</div>
|
||
<div class="quickadd-preview" id="quickadd-preview"></div>
|
||
<div class="quickadd-hint">#kategori-eller-tag · @eier (@me) · p1–p4 · !frist (2026-06-20, +3d, idag, imorgen) · ~timer · loc:sted · resten blir tittel</div>
|
||
</div>
|
||
|
||
<section class="kpi-row">
|
||
<div class="kpi">
|
||
<div class="kpi-label">Åpne oppgaver</div>
|
||
<div class="kpi-value" id="kpi-open">0</div>
|
||
<div class="kpi-sub" id="kpi-open-sub">av 0 totalt</div>
|
||
</div>
|
||
<div class="kpi kpi-me">
|
||
<div class="kpi-label">Mine åpne</div>
|
||
<div class="kpi-value" id="kpi-mine">0</div>
|
||
<div class="kpi-sub" id="kpi-mine-sub">tildelt meg</div>
|
||
</div>
|
||
<div class="kpi kpi-p1">
|
||
<div class="kpi-label">P1 Kritisk</div>
|
||
<div class="kpi-value" id="kpi-p1">0</div>
|
||
<div class="kpi-sub">umiddelbar handling</div>
|
||
</div>
|
||
<div class="kpi kpi-warn">
|
||
<div class="kpi-label">Est. tid igjen</div>
|
||
<div class="kpi-value" id="kpi-hours">0t</div>
|
||
<div class="kpi-sub" id="kpi-hours-sub">arbeidstimer</div>
|
||
</div>
|
||
<div class="kpi">
|
||
<div class="kpi-label">Forfalte</div>
|
||
<div class="kpi-value" id="kpi-overdue">0</div>
|
||
<div class="kpi-sub">over frist</div>
|
||
</div>
|
||
<div class="kpi kpi-ok">
|
||
<div class="kpi-label">Ferdig (7d)</div>
|
||
<div class="kpi-value" id="kpi-done">0</div>
|
||
<div class="kpi-sub">siste 7 dager</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="chart-row" id="chart-row">
|
||
<div class="panel">
|
||
<h3>Åpne oppgaver per kategori <span id="cat-total" style="color:var(--text-faint);font-family:var(--mono);text-transform:none;letter-spacing:0"></span></h3>
|
||
<div class="chart-wrap"><canvas id="catChart"></canvas></div>
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Fordeling etter prioritet</h3>
|
||
<div class="chart-wrap"><canvas id="prioChart"></canvas></div>
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Åpne oppgaver per eier</h3>
|
||
<div class="chart-wrap"><canvas id="ownerChart"></canvas></div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="filters">
|
||
<div class="view-toggle">
|
||
<button id="view-board" title="Tavle (v)">▦ Tavle</button>
|
||
<button id="view-table" title="Tabell (v)">☰ Tabell</button>
|
||
<button id="view-plan" title="Dagsplan (p)">📅 Dagsplan</button>
|
||
</div>
|
||
<div class="filter-group" id="fg-status">
|
||
<label>Status</label>
|
||
<select id="f-status">
|
||
<option value="open">Åpne</option>
|
||
<option value="all">Alle</option>
|
||
<option value="todo">Å gjøre</option>
|
||
<option value="progress">Pågår</option>
|
||
<option value="blocked">Blokkert</option>
|
||
<option value="done">Ferdig</option>
|
||
</select>
|
||
</div>
|
||
<div class="filter-group">
|
||
<label>Kategori</label>
|
||
<select id="f-category"><option value="all">Alle</option></select>
|
||
</div>
|
||
<div class="filter-group">
|
||
<label>Prioritet</label>
|
||
<select id="f-priority">
|
||
<option value="all">Alle</option>
|
||
<option value="P1">P1 Kritisk</option>
|
||
<option value="P2">P2 Høy</option>
|
||
<option value="P3">P3 Middels</option>
|
||
<option value="P4">P4 Lav</option>
|
||
</select>
|
||
</div>
|
||
<div class="filter-group">
|
||
<label>Eier</label>
|
||
<select id="f-owner">
|
||
<option value="all">Alle</option>
|
||
<option value="__me__">Meg</option>
|
||
<option value="__unassigned__">Utildelt</option>
|
||
</select>
|
||
</div>
|
||
<input class="search-input" type="text" id="f-search" placeholder="Søk tittel, beskrivelse, lokasjon, tag … (/)">
|
||
<button id="clearFilters">Nullstill</button>
|
||
</div>
|
||
|
||
<section class="board" id="board" style="display:none"></section>
|
||
|
||
<section class="planner" id="planner" style="display:none">
|
||
<div class="plan-col">
|
||
<div class="plan-col-head">
|
||
<h3>Tilgjengelige oppgaver <span class="col-meta" id="plan-avail-count"></span></h3>
|
||
<span class="plan-col-hint">klikk + for å planlegge</span>
|
||
</div>
|
||
<div class="plan-col-body" id="plan-available-body"></div>
|
||
</div>
|
||
<div class="plan-col plan-today">
|
||
<div class="plan-col-head">
|
||
<div class="plan-date-row">
|
||
<h3>Dagsplan</h3>
|
||
<input type="date" id="plan-date" title="Velg dag å planlegge">
|
||
</div>
|
||
<span class="col-meta" id="plan-capacity"></span>
|
||
</div>
|
||
<div class="plan-col-body" id="plan-today-body"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="table-panel" id="table-panel" style="display:none">
|
||
<div class="table-head">
|
||
<h3>Oppgaveliste <span class="count" id="tbl-count">0</span></h3>
|
||
<div class="sub" style="color:var(--text-faint); font-family:var(--mono); font-size:11px">klikk kolonne for å sortere</div>
|
||
</div>
|
||
<div class="table-scroll">
|
||
<table id="tbl">
|
||
<thead>
|
||
<tr>
|
||
<th data-sort="priority" style="width:70px">Prio</th>
|
||
<th data-sort="title">Oppgave</th>
|
||
<th data-sort="category" style="width:110px">Kategori</th>
|
||
<th data-sort="status" style="width:100px">Status</th>
|
||
<th data-sort="owner" style="width:130px">Eier</th>
|
||
<th data-sort="location" style="width:120px">Lokasjon</th>
|
||
<th data-sort="estHours" style="width:70px;text-align:right">Est (t)</th>
|
||
<th data-sort="deadline" style="width:110px">Frist</th>
|
||
<th style="width:120px;text-align:right">Handling</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tbl-body"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="empty" class="empty-state" style="display:none">
|
||
Ingen oppgaver matcher filtrene.
|
||
<div id="empty-seed" style="display:none;margin-top:14px">
|
||
Tom database. <button id="seedBtn" class="primary">Last inn eksempel-data</button>
|
||
</div>
|
||
</div>
|
||
|
||
<footer>
|
||
Sanntidssynk via WebSocket · snarveier:
|
||
<span class="kbd">n</span> ny ·
|
||
<span class="kbd">/</span> søk ·
|
||
<span class="kbd">v</span> bytt visning ·
|
||
<span class="kbd">p</span> dagsplan ·
|
||
<span class="kbd">a</span> aktivitet ·
|
||
<span class="kbd">esc</span> lukk
|
||
</footer>
|
||
</div>
|
||
|
||
<aside class="drawer" id="drawer">
|
||
<div class="drawer-head">
|
||
<h2>Aktivitet</h2>
|
||
<button class="icon-btn" id="drawer-close" style="font-size:18px">×</button>
|
||
</div>
|
||
<div class="drawer-body" id="drawer-body"></div>
|
||
</aside>
|
||
|
||
<div class="modal-overlay" id="modal">
|
||
<div class="modal">
|
||
<div class="modal-head">
|
||
<h2 id="modal-title">Ny oppgave</h2>
|
||
<button class="icon-btn" id="modal-close" style="font-size:18px">×</button>
|
||
</div>
|
||
<div class="modal-warning" id="modal-warning"></div>
|
||
<div class="modal-body">
|
||
<div class="form-field full">
|
||
<label>Tittel *</label>
|
||
<input type="text" id="f-title" placeholder="F.eks. Konfigurer BGP-peer mot AS2119">
|
||
</div>
|
||
<div class="form-field full">
|
||
<label>Beskrivelse / notater</label>
|
||
<textarea id="f-desc" placeholder="Kommandoer, konfigurasjon, referanser …"></textarea>
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Kategori *</label>
|
||
<select id="f-cat"></select>
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Prioritet</label>
|
||
<select id="f-prio">
|
||
<option value="P1">P1 Kritisk</option>
|
||
<option value="P2" selected>P2 Høy</option>
|
||
<option value="P3">P3 Middels</option>
|
||
<option value="P4">P4 Lav</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Status</label>
|
||
<select id="f-stat">
|
||
<option value="todo" selected>Å gjøre</option>
|
||
<option value="progress">Pågår</option>
|
||
<option value="blocked">Blokkert</option>
|
||
<option value="done">Ferdig</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Est. tid (timer)</label>
|
||
<input type="number" id="f-est" min="0" step="0.5" placeholder="2">
|
||
</div>
|
||
<div class="form-field full">
|
||
<label>Eier / tildelt</label>
|
||
<div class="owner-input-row">
|
||
<input type="text" id="f-owner-input" placeholder="brukernavn, eller blank for utildelt">
|
||
<select id="f-owner-select" title="Velg eksisterende bruker">
|
||
<option value="">— velg —</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Lokasjon / site</label>
|
||
<input type="text" id="f-loc" placeholder="DC-OSL-1, Bergen POP, remote …">
|
||
</div>
|
||
<div class="form-field">
|
||
<label>Frist</label>
|
||
<input type="date" id="f-dl">
|
||
</div>
|
||
<div class="form-field full">
|
||
<label>Tags (komma-separert)</label>
|
||
<input type="text" id="f-tags" placeholder="vedlikeholdsvindu, kunde-X, audit">
|
||
</div>
|
||
<div class="form-field full status-note-field" id="f-statusnote-field" style="display:none">
|
||
<label id="f-statusnote-label">Avslutningskommentar (valgfritt)</label>
|
||
<input type="text" id="f-statusnote" placeholder="Legges som kommentar når du lagrer">
|
||
</div>
|
||
<div class="comments-section" id="comments-section" style="display:none">
|
||
<h4>Kommentarer <span id="comment-count" style="font-family:var(--mono)"></span></h4>
|
||
<div id="comments-list"></div>
|
||
<div class="comment-input-row">
|
||
<input type="text" id="comment-input" placeholder="Skriv en kommentar … (enter for å sende)">
|
||
<button id="comment-send">Send</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="danger" id="modal-delete" style="display:none">Slett</button>
|
||
<span id="modal-audit" style="flex:1;font-size:11px;color:var(--text-faint);font-family:var(--mono)"></span>
|
||
<button id="modal-cancel">Avbryt</button>
|
||
<button class="primary" id="modal-save">Lagre</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-overlay" id="status-modal">
|
||
<div class="modal" style="max-width:460px">
|
||
<div class="modal-head">
|
||
<h2 id="status-modal-title">Kommentar</h2>
|
||
<button class="icon-btn" id="status-modal-close" style="font-size:18px">×</button>
|
||
</div>
|
||
<div class="modal-body" style="grid-template-columns:1fr">
|
||
<div class="form-field full">
|
||
<label id="status-modal-label">Legg til en kommentar (valgfritt)</label>
|
||
<textarea id="status-comment" placeholder="F.eks. hva som ble gjort, eller hva som blokkerer …"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<span style="flex:1;font-size:11px;color:var(--text-faint)">⏎ for å lagre · Esc for å avbryte</span>
|
||
<button id="status-skip">Hopp over</button>
|
||
<button class="primary" id="status-save">Lagre</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toast-stack" id="toast-stack"></div>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|