Files
voltage-monitor/templates/index.html
Mateusz Gruszczyński 6bd4b525b1 error pages
2026-03-02 10:47:28 +01:00

218 lines
7.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends 'base.html' %}
{% block content %}
<!-- HEADER -->
<div class="vm-card p-3 mb-3">
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2">
<div>
<div class="d-flex align-items-center gap-2">
<i class="fa-solid fa-bolt text-warning"></i>
<h4 class="mb-0">VoltMonitor</h4>
</div>
<div class="text-muted small mt-1">Sieć trójfazowa • Rokietnica, Gajowa</div>
</div>
<div class="d-flex align-items-center gap-2 flex-wrap">
<span class="badge bg-dark border border-secondary text-muted" id="lastUpdate" style="font-size:.72rem;">Ładowanie…</span>
<span class="badge bg-dark border border-secondary text-muted" style="font-size:.72rem;">
PN-EN 50160: <span class="text-success fw-semibold">207253V</span>
</span>
</div>
</div>
</div>
<!-- GAUGES -->
<div class="vm-card p-3 mb-3">
<div class="d-flex align-items-center justify-content-between mb-2">
<h6 class="mb-0"><i class="fa-solid fa-gauge-high me-2 text-info"></i>Dane chwilowe</h6>
<span class="text-muted small">live</span>
</div>
<div class="gauge-grid mb-0">
{% for id, phase in phases.items() %}
<div class="gauge-card">
<div class="gauge-canvas-container"><canvas id="gauge{{ id }}"></canvas></div>
<div class="gauge-label">{{ phase.label }}</div>
<div class="voltage-value" id="value{{ id }}">---</div>
</div>
{% endfor %}
</div>
</div>
<!-- CONTROLS -->
<div class="vm-card p-3 mb-3">
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2 mb-2">
<h6 class="mb-0"><i class="fa-solid fa-chart-line me-2 text-primary"></i>Wykres</h6>
<div class="text-muted small">Zakres • zoom/pan • przeciągnięcie = precyzyjny wybór</div>
</div>
<div class="time-selector-wrapper mb-0">
{% for key, r in time_ranges.items() %}
<button class="btn btn-sm btn-outline-primary time-btn {% if key == default_range %}active{% endif %}"
data-range="{{ key }}" onclick="changeTimeRange('{{ key }}')">
<i class="fa-regular fa-clock me-1"></i>{{ key }}
</button>
{% endfor %}
<button class="btn btn-sm btn-outline-primary time-btn" id="customRangeBtn" onclick="openCustomRangePicker()">
<i class="fa-solid fa-calendar-days me-1"></i>Własny
</button>
</div>
</div>
<!-- Modal: custom range -->
<div id="customRangeModal">
<div class="modal-content">
<h3 class="d-flex align-items-center gap-2">
<i class="fa-solid fa-calendar-days text-primary"></i>Własny zakres
</h3>
<div class="modal-form-group">
<label class="modal-label">Data i czas od:</label>
<input type="datetime-local" id="customStartDate" class="modal-input">
</div>
<div class="modal-form-group">
<label class="modal-label">Data i czas do:</label>
<input type="datetime-local" id="customEndDate" class="modal-input">
</div>
<div class="modal-buttons">
<button onclick="closeCustomRangePicker()" class="modal-btn modal-btn-cancel">
<i class="fa-solid fa-xmark me-1"></i>Anuluj
</button>
<button onclick="applyCustomRange()" class="modal-btn modal-btn-apply">
<i class="fa-solid fa-check me-1"></i>Zastosuj
</button>
</div>
</div>
</div>
<!-- CHART -->
<div class="main-chart-card mb-3" style="position:relative;">
<span id="chartRangeDisplay" class="chart-range-badge"></span>
<canvas id="voltageChart"></canvas>
</div>
<!-- EVENTS -->
<div class="events-card mb-3">
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap gap-2">
<h6 class="mb-0"><i class="fa-solid fa-list-ul me-2 text-warning"></i>Dziennik zdarzeń</h6>
<span id="eventRangeLabel" class="text-muted" style="font-size:.75rem;">Ładowanie…</span>
</div>
<div id="eventLogContainer">
<div class="no-events"><i class="fa-solid fa-spinner fa-spin me-2"></i>Ładowanie zdarzeń…</div>
</div>
</div>
<!-- Modal: API Helper -->
<div id="apiHelperModal">
<div class="modal-content vm-modal-wide">
<div class="vm-modal-head">
<h3 class="m-0 d-flex align-items-center gap-2">
<i class="fa-solid fa-code text-info"></i>API Helper
</h3>
<button class="vm-icon-btn" type="button" id="closeApiHelperBtn" title="Zamknij">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="vm-modal-grid">
<div>
<label class="modal-label">Endpoint</label>
<select id="apiEndpoint" class="modal-input">
<option value="/api/timeseries/1">/api/timeseries/1</option>
<option value="/api/timeseries/2">/api/timeseries/2</option>
<option value="/api/timeseries/3">/api/timeseries/3</option>
<option value="/api/events">/api/events</option>
<option value="/api/outages/1">/api/outages/1</option>
<option value="/api/outages/2">/api/outages/2</option>
<option value="/api/outages/3">/api/outages/3</option>
</select>
</div>
<div>
<label class="modal-label">range (opcjonalnie)</label>
<div class="vm-range-quick">
<button type="button" class="vm-range-btn" data-range="6h">6h</button>
<button type="button" class="vm-range-btn" data-range="12h">12h</button>
<button type="button" class="vm-range-btn" data-range="24h">24h</button>
<button type="button" class="vm-range-btn" data-range="7d">7d</button>
<button type="button" class="vm-range-btn" data-range="30d">30d</button>
</div>
<input id="apiRange" class="modal-input mt-2" placeholder="np. 24h / 7d">
</div>
<div>
<label class="modal-label">start (opcjonalnie)</label>
<input id="apiStart" type="datetime-local" class="modal-input">
</div>
<div>
<label class="modal-label">end (opcjonalnie)</label>
<input id="apiEnd" type="datetime-local" class="modal-input">
</div>
</div>
<div class="vm-modal-block">
<label class="modal-label">URL</label>
<div class="vm-inline">
<input id="apiUrlOutput" class="modal-input vm-mono" readonly>
<button class="modal-btn modal-btn-apply" type="button" id="copyApiUrlBtn">
<i class="fa-regular fa-copy me-1"></i>Kopiuj
</button>
</div>
</div>
<div class="vm-modal-block">
<label class="modal-label">curl</label>
<div class="vm-inline">
<input id="apiCurlOutput" class="modal-input vm-mono" readonly>
<button class="modal-btn modal-btn-cancel" type="button" id="copyCurlBtn">
<i class="fa-regular fa-copy me-1"></i>Kopiuj
</button>
</div>
</div>
<div class="vm-modal-actions">
<button class="modal-btn modal-btn-cancel" type="button" id="genApiBtn">
<i class="fa-solid fa-link me-1"></i>Generuj
</button>
<button class="modal-btn modal-btn-apply" type="button" id="callApiBtn">
<i class="fa-solid fa-play me-1"></i>Wyślij
</button>
</div>
<div class="vm-modal-block">
<label class="modal-label">Response</label>
<pre id="apiResponse" class="vm-pre">(pusto)</pre>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ static_v('js/gauge.js') }}"></script>
<script src="{{ static_v('js/state.js') }}"></script>
<script src="{{ static_v('js/chart.js') }}"></script>
<script src="{{ static_v('js//events.js') }}"></script>
<script src="{{ static_v('js/data.js') }}"></script>
<script src="{{ static_v('js/socket.js') }}"></script>
<script src="{{ static_v('js/index.js') }}"></script>
<script src="{{ static_v('js/modal.js') }}"></script>
<script src="{{ static_v('js/apiHelper.js') }}"></script>
<script src="{{ static_v('js/pageInit.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
initPage({{ phases|tojson }}, '{{ default_range }}');
});
</script>
{% endblock %}