Feb 27 2026: update Issue view details

This commit is contained in:
2026-02-27 17:45:04 -05:00
parent 1ee621bf58
commit 0cf36a2f41
5 changed files with 72 additions and 6 deletions
+20
View File
@@ -2,6 +2,23 @@ from app import db
from datetime import datetime
class IssueComment(db.Model):
__tablename__ = 'issue_comments'
id = db.Column(db.Integer, primary_key=True)
issue_id = db.Column(db.Integer, db.ForeignKey('issues.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
status_at_time = db.Column(db.String(20)) # snapshot of issue status when comment was made
body = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
# Relationships
author = db.relationship('User', foreign_keys=[user_id])
def __repr__(self):
return f'<IssueComment {self.id} issue={self.issue_id}>'
class Issue(db.Model):
__tablename__ = 'issues'
@@ -20,6 +37,9 @@ class Issue(db.Model):
# Relationships
assigned_user = db.relationship('User', foreign_keys=[assigned_to], backref='assigned_issues')
comments = db.relationship('IssueComment', backref='issue', lazy='dynamic',
order_by='IssueComment.created_at',
cascade='all, delete-orphan')
def __repr__(self):
return f'<Issue {self.id} - {self.severity}>'
+16 -4
View File
@@ -3,7 +3,7 @@ from flask import (Blueprint, render_template, redirect, url_for,
flash, request, current_app)
from flask_login import login_required, current_user
from app import db
from app.models.issue import Issue
from app.models.issue import Issue, IssueComment
from app.models.facility import Facility, Area
from app.models.user import User
from app.utils.forms import IssueForm, IssueUpdateForm
@@ -84,15 +84,27 @@ def view(issue_id):
existing = issue.result_photos or []
issue.result_photos = existing + new_photos
# Persist a comment entry if the user wrote update notes
comment_body = form.comments.data.strip() if form.comments.data else ''
if comment_body:
comment = IssueComment(
issue_id = issue.id,
user_id = current_user.id,
status_at_time = issue.status,
body = comment_body,
)
db.session.add(comment)
db.session.commit()
current_app.logger.info(
'ISSUE UPDATED | id=%s | status=%s | result_photos_added=%s | updated_by=%s',
issue.id, issue.status, len(new_photos), current_user.username
'ISSUE UPDATED | id=%s | status=%s | result_photos_added=%s | comment=%s | updated_by=%s',
issue.id, issue.status, len(new_photos), bool(comment_body), current_user.username
)
flash('Issue updated.', 'success')
return redirect(url_for('issues.view', issue_id=issue_id))
return render_template('issues/view.html', issue=issue, form=form)
comments = issue.comments.order_by(IssueComment.created_at.asc()).all()
return render_template('issues/view.html', issue=issue, form=form, comments=comments)
# ── Standalone create (not from an inspection) ────────────────────────────────
+7 -1
View File
@@ -46,7 +46,13 @@ def index():
total_inspections = base.count()
completed = base.filter(Inspection.status == 'completed').count()
flagged = base.filter(Inspection.status == 'flagged').count()
# "Flagged" = open or in-progress issues logged within the date range,
# not inspections with status='flagged' (those get completed on submit).
flagged = Issue.query.filter(
Issue.reported_at >= start,
Issue.reported_at <= end,
Issue.status != 'resolved',
).count()
avg_score = db.session.query(func.avg(Inspection.overall_score)).filter(
Inspection.inspection_date >= start,
Inspection.inspection_date <= end,
+28
View File
@@ -69,6 +69,34 @@
{% endif %}
</div>
</div>
{# ── Update History ─────────────────────────────────────────────────── #}
{% if comments %}
<div class="card shadow-sm mb-4">
<div class="card-header bg-light">
<h6 class="mb-0"><i class="bi bi-clock-history"></i> Update History</h6>
</div>
<ul class="list-group list-group-flush">
{% for c in comments %}
<li class="list-group-item">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="fw-semibold text-dark">
<i class="bi bi-person-circle"></i> {{ c.author.username }}
</span>
<span class="d-flex align-items-center gap-2">
<span class="badge bg-{{ 'success' if c.status_at_time == 'resolved' else 'warning text-dark' if c.status_at_time == 'in_progress' else 'danger' }} rounded-pill" style="font-size:.65rem;">
{{ c.status_at_time|replace('_',' ')|title }}
</span>
<small class="text-muted">{{ c.created_at.strftime('%Y-%m-%d %H:%M') }}</small>
</span>
</div>
<p class="mb-0 text-secondary" style="white-space:pre-wrap; font-size:.9rem;">{{ c.body }}</p>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
<div class="col-lg-4">
+1 -1
View File
@@ -52,7 +52,7 @@
{% for label, value, color, icon in [
('Total Inspections', total_inspections, 'primary', 'bi-clipboard-data'),
('Completed', completed, 'success', 'bi-check-circle'),
('Flagged', flagged, 'danger', 'bi-flag'),
('Open Issues', flagged, 'danger', 'bi-flag'),
('Avg Score', (avg_score|string + '%') if avg_score else '—', 'info', 'bi-graph-up'),
] %}
<div class="col-md-3 mb-3">