05/26 Add Contract filter in Issues page
This commit is contained in:
+24
-8
@@ -108,11 +108,20 @@ def index():
|
|||||||
status_filter = request.args.get('status', '')
|
status_filter = request.args.get('status', '')
|
||||||
sla_filter = request.args.get('sla', '')
|
sla_filter = request.args.get('sla', '')
|
||||||
facility_filter = request.args.get('facility_id', '')
|
facility_filter = request.args.get('facility_id', '')
|
||||||
|
contract_filter = request.args.get('contract_id', '')
|
||||||
|
|
||||||
if severity_filter:
|
if severity_filter:
|
||||||
q = q.filter(Issue.severity == severity_filter)
|
q = q.filter(Issue.severity == severity_filter)
|
||||||
if status_filter:
|
if status_filter:
|
||||||
q = q.filter(Issue.status == status_filter)
|
q = q.filter(Issue.status == status_filter)
|
||||||
|
if contract_filter.isdigit():
|
||||||
|
_contract_fids = [
|
||||||
|
f.id for f in Facility.query.filter_by(project_id=int(contract_filter)).all()
|
||||||
|
]
|
||||||
|
q = q.filter(db.or_(
|
||||||
|
Issue.facility_id.in_(_contract_fids),
|
||||||
|
Area.facility_id.in_(_contract_fids),
|
||||||
|
)) if _contract_fids else q.filter(False)
|
||||||
if facility_filter:
|
if facility_filter:
|
||||||
fid = int(facility_filter)
|
fid = int(facility_filter)
|
||||||
q = q.filter(
|
q = q.filter(
|
||||||
@@ -144,19 +153,24 @@ def index():
|
|||||||
for f in IssueFollower.query.filter_by(user_id=current_user.id).all()
|
for f in IssueFollower.query.filter_by(user_id=current_user.id).all()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Facilities for the filter dropdown — scoped for inspectors/customers
|
# Facilities for the filter dropdown — scoped for inspectors/customers,
|
||||||
|
# then narrowed to the selected contract when contract_filter is active.
|
||||||
if current_user.role == 'inspector':
|
if current_user.role == 'inspector':
|
||||||
fids = get_inspector_scope(current_user) or []
|
fids = get_inspector_scope(current_user) or []
|
||||||
facilities = Facility.query.filter(
|
_fq = Facility.query.filter(Facility.id.in_(fids), Facility.active == True)
|
||||||
Facility.id.in_(fids), Facility.active == True
|
|
||||||
).order_by(Facility.name).all()
|
|
||||||
elif current_user.role == 'customer':
|
elif current_user.role == 'customer':
|
||||||
facility_ids = get_customer_scope(current_user) or []
|
facility_ids = get_customer_scope(current_user) or []
|
||||||
facilities = Facility.query.filter(
|
_fq = Facility.query.filter(Facility.id.in_(facility_ids), Facility.active == True)
|
||||||
Facility.id.in_(facility_ids), Facility.active == True
|
|
||||||
).order_by(Facility.name).all()
|
|
||||||
else:
|
else:
|
||||||
facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all()
|
_fq = Facility.query.filter_by(active=True)
|
||||||
|
|
||||||
|
if contract_filter.isdigit():
|
||||||
|
_fq = _fq.filter(Facility.project_id == int(contract_filter))
|
||||||
|
|
||||||
|
facilities = _fq.order_by(Facility.name).all()
|
||||||
|
|
||||||
|
from app.models.project import Project
|
||||||
|
projects = Project.query.filter_by(active=True).order_by(Project.name).all()
|
||||||
|
|
||||||
# Staff for quick-assign dropdown — same roles as the full issue form
|
# Staff for quick-assign dropdown — same roles as the full issue form
|
||||||
staff = User.query.filter(
|
staff = User.query.filter(
|
||||||
@@ -169,7 +183,9 @@ def index():
|
|||||||
status_filter=status_filter,
|
status_filter=status_filter,
|
||||||
sla_filter=sla_filter,
|
sla_filter=sla_filter,
|
||||||
facility_filter=facility_filter,
|
facility_filter=facility_filter,
|
||||||
|
contract_filter=contract_filter,
|
||||||
facilities=facilities,
|
facilities=facilities,
|
||||||
|
projects=projects,
|
||||||
staff=staff,
|
staff=staff,
|
||||||
followed_ids=followed_ids)
|
followed_ids=followed_ids)
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,18 @@
|
|||||||
<option value="ok" {{ 'selected' if sla_filter == 'ok' }}>OK</option>
|
<option value="ok" {{ 'selected' if sla_filter == 'ok' }}>OK</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label small mb-1">Contract</label>
|
||||||
|
<select name="contract_id" id="filter_contract_id" class="form-select form-select-sm">
|
||||||
|
<option value="">All Contracts</option>
|
||||||
|
{% for p in projects %}
|
||||||
|
<option value="{{ p.id }}" {{ 'selected' if contract_filter == p.id|string }}>{{ p.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<label class="form-label small mb-1">Facility</label>
|
<label class="form-label small mb-1">Facility</label>
|
||||||
<select name="facility_id" class="form-select form-select-sm">
|
<select name="facility_id" id="filter_facility_id" class="form-select form-select-sm">
|
||||||
<option value="">All Facilities</option>
|
<option value="">All Facilities</option>
|
||||||
{% for f in facilities %}
|
{% for f in facilities %}
|
||||||
<option value="{{ f.id }}" {{ 'selected' if facility_filter == f.id|string }}>{{ f.name }}</option>
|
<option value="{{ f.id }}" {{ 'selected' if facility_filter == f.id|string }}>{{ f.name }}</option>
|
||||||
@@ -139,7 +148,7 @@
|
|||||||
class="d-inline"
|
class="d-inline"
|
||||||
title="Unfollow this issue">
|
title="Unfollow this issue">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<input type="hidden" name="next" value="{{ url_for('issues.index', page=issues.page, severity=severity_filter, status=status_filter, facility_id=facility_filter) }}">
|
<input type="hidden" name="next" value="{{ url_for('issues.index', page=issues.page, severity=severity_filter, status=status_filter, contract_id=contract_filter, facility_id=facility_filter) }}">
|
||||||
<button type="submit" class="btn btn-sm btn-outline-primary p-0 px-1 me-1"
|
<button type="submit" class="btn btn-sm btn-outline-primary p-0 px-1 me-1"
|
||||||
title="Unfollow">
|
title="Unfollow">
|
||||||
<i class="bi bi-bell-slash" style="font-size:.75rem;"></i>
|
<i class="bi bi-bell-slash" style="font-size:.75rem;"></i>
|
||||||
@@ -180,7 +189,7 @@
|
|||||||
{% if p %}
|
{% if p %}
|
||||||
<li class="page-item {{ 'active' if p == issues.page }}">
|
<li class="page-item {{ 'active' if p == issues.page }}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('issues.index', page=p, severity=severity_filter, status=status_filter, sla=sla_filter, facility_id=facility_filter) }}">{{ p }}</a>
|
href="{{ url_for('issues.index', page=p, severity=severity_filter, status=status_filter, sla=sla_filter, contract_id=contract_filter, facility_id=facility_filter) }}">{{ p }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}<li class="page-item disabled"><span class="page-link">…</span></li>{% endif %}
|
{% else %}<li class="page-item disabled"><span class="page-link">…</span></li>{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -196,6 +205,41 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
var contractSel = document.getElementById('filter_contract_id');
|
||||||
|
var facilitySel = document.getElementById('filter_facility_id');
|
||||||
|
if (!contractSel || !facilitySel) return;
|
||||||
|
|
||||||
|
var FACILITIES_URL = '{{ url_for("inspections.facilities_for_project", project_id=0) }}'.replace('/0', '/');
|
||||||
|
|
||||||
|
contractSel.addEventListener('change', function () {
|
||||||
|
var projectId = this.value;
|
||||||
|
facilitySel.value = ''; // reset facility selection
|
||||||
|
if (!projectId) {
|
||||||
|
// No contract selected — restore all-facilities placeholder and submit
|
||||||
|
// (server will return unfiltered facility list)
|
||||||
|
facilitySel.innerHTML = '<option value="">All Facilities</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
facilitySel.disabled = true;
|
||||||
|
facilitySel.innerHTML = '<option value="">Loading…</option>';
|
||||||
|
fetch(FACILITIES_URL + projectId)
|
||||||
|
.then(function (r) { return r.json(); })
|
||||||
|
.then(function (data) {
|
||||||
|
var html = '<option value="">All Facilities</option>';
|
||||||
|
data.forEach(function (f) {
|
||||||
|
html += '<option value="' + f.id + '">' + f.name + '</option>';
|
||||||
|
});
|
||||||
|
facilitySel.innerHTML = html;
|
||||||
|
facilitySel.disabled = false;
|
||||||
|
})
|
||||||
|
.catch(function () { facilitySel.disabled = false; });
|
||||||
|
});
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
|
||||||
{% if current_user.role in ['admin', 'director'] %}
|
{% if current_user.role in ['admin', 'director'] %}
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user