162 lines
6.9 KiB
HTML
162 lines
6.9 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ title }}{% endblock %}
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-8">
|
|
<h2 class="mb-4"><i class="bi bi-calendar2-week"></i> {{ title }}</h2>
|
|
|
|
<form method="POST" class="card shadow-sm">
|
|
<div class="card-body">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Schedule name</label>
|
|
<input type="text" name="name" class="form-control" required
|
|
value="{{ schedule.name if schedule else '' }}"
|
|
placeholder="e.g. Weekly restroom check — Main Office">
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Template</label>
|
|
<select name="template_id" class="form-select" required>
|
|
<option value="">— Choose a template —</option>
|
|
{% for t in templates %}
|
|
<option value="{{ t.id }}"
|
|
{{ 'selected' if schedule and schedule.template_id == t.id }}>{{ t.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Frequency</label>
|
|
<select name="frequency" class="form-select" required>
|
|
{% for f in frequencies %}
|
|
<option value="{{ f }}"
|
|
{{ 'selected' if (schedule and schedule.frequency == f) or (not schedule and f == 'weekly') }}>
|
|
{{ f|title }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Mode</label>
|
|
<select name="mode" class="form-select">
|
|
<option value="auto" {{ 'selected' if not schedule or schedule.mode != 'plan' }}>
|
|
Auto — create the inspection automatically each period</option>
|
|
<option value="plan" {{ 'selected' if schedule and schedule.mode == 'plan' }}>
|
|
Plan — inspector presses Start (with due/overdue reminders)</option>
|
|
</select>
|
|
<div class="form-text">
|
|
Auto drops an in-progress inspection into the inspector's queue on
|
|
schedule. Plan assigns a due date and reminds them the day before, on
|
|
the day, and alerts managers once it's overdue.
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Notes for the inspector <span class="text-muted small">(optional)</span></label>
|
|
<textarea name="notes" class="form-control" rows="2"
|
|
placeholder="Anything the inspector should know before starting">{{ schedule.notes if schedule and schedule.notes else '' }}</textarea>
|
|
<div class="form-text">Copied onto the inspection when it starts.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Facility</label>
|
|
<select name="facility_id" id="facilitySelect" class="form-select" required>
|
|
<option value="">— Choose a facility —</option>
|
|
{% for f in facilities %}
|
|
<option value="{{ f.id }}"
|
|
{{ 'selected' if schedule and schedule.facility_id == f.id }}>{{ f.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Area <span class="text-muted small">(optional)</span></label>
|
|
<select name="area_id" id="areaSelect" class="form-select">
|
|
<option value="">— Whole facility —</option>
|
|
{% if schedule and schedule.area %}
|
|
<option value="{{ schedule.area.id }}" selected>{{ schedule.area.name }}</option>
|
|
{% endif %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Assign to inspector</label>
|
|
<select name="inspector_id" class="form-select" required>
|
|
<option value="">— Choose an inspector —</option>
|
|
{% for u in inspectors %}
|
|
<option value="{{ u.id }}"
|
|
{{ 'selected' if schedule and schedule.inspector_id == u.id }}>
|
|
{{ u.display_name }} ({{ u.role }})</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
{% if schedule %}
|
|
<div class="form-check form-switch mb-1">
|
|
<input class="form-check-input" type="checkbox" name="active" id="activeSwitch"
|
|
{{ 'checked' if schedule.active }}>
|
|
<label class="form-check-label" for="activeSwitch">Active</label>
|
|
</div>
|
|
<p class="text-muted small">
|
|
Saving recomputes the next {{ 'due date' if schedule.mode == 'plan' else 'run' }}
|
|
from now, and resets this occurrence's reminders. Currently:
|
|
{{ schedule.next_run_at.strftime('%Y-%m-%d %H:%M') if schedule.next_run_at else '—' }}
|
|
{% if schedule.last_completed_at %}
|
|
· last completed {{ schedule.last_completed_at.strftime('%Y-%m-%d %H:%M') }}
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="card-footer d-flex justify-content-between">
|
|
<a href="{{ url_for('inspection_schedules.index') }}" class="btn btn-outline-secondary">Cancel</a>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-lg"></i> Save Schedule
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Facility → Area cascade, reusing the existing inspections AJAX endpoint.
|
|
(function () {
|
|
var facilitySelect = document.getElementById('facilitySelect');
|
|
var areaSelect = document.getElementById('areaSelect');
|
|
if (!facilitySelect || !areaSelect) return;
|
|
|
|
var preselectedAreaId = {{ (schedule.area_id if schedule and schedule.area_id else 0) | tojson }};
|
|
|
|
function loadAreas(facilityId, keepSelection) {
|
|
areaSelect.innerHTML = '<option value="">— Whole facility —</option>';
|
|
if (!facilityId) return;
|
|
fetch('{{ url_for('inspections.areas_for_facility', facility_id=0) }}'.replace('/0', '/' + facilityId))
|
|
.then(function (r) { return r.json(); })
|
|
.then(function (areas) {
|
|
areas.forEach(function (a) {
|
|
var opt = document.createElement('option');
|
|
opt.value = a.id;
|
|
opt.textContent = a.name;
|
|
if (keepSelection && a.id === preselectedAreaId) opt.selected = true;
|
|
areaSelect.appendChild(opt);
|
|
});
|
|
})
|
|
.catch(function () { /* leave the whole-facility default in place */ });
|
|
}
|
|
|
|
facilitySelect.addEventListener('change', function () {
|
|
preselectedAreaId = 0;
|
|
loadAreas(this.value, false);
|
|
});
|
|
|
|
// On edit load, refresh the area list for the saved facility and keep the saved area.
|
|
if (facilitySelect.value) loadAreas(facilitySelect.value, true);
|
|
})();
|
|
</script>
|
|
{% endblock %}
|