loopable / platform /modules /feedback.py
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
c14ceee verified
Raw
History Blame Contribute Delete
2.47 kB
"""Feedback module β€” feature requests / feedback / bug reports from every user.
Sits OUTSIDE the Dashboards/Workflows nav groups (its own sidebar entry). Submissions accumulate
in the platform's writable HF Dataset store (core/store.py, key 'feedback') so they survive
restarts and are shared across users/instances. The record shape is deliberately structured so an
AI staging pass can later triage items into the build workflow (type/module/importance/status +
free-text details). No Odoo involvement at all β€” this module never touches ERP data.
Statuses: New (just submitted) -> Staged (AI/owner queued it for a build cycle) -> Planned ->
Done | Declined. Triage is admin-only; submitting is open to every signed-in user.
"""
import time
import datetime as dt
import core.store as store
KEY = 'feedback'
TYPES = ['Feature request', 'Feedback', 'Bug']
IMPORTANCE = ['Must have', 'Nice to have', 'Idea']
STATUSES = ['New', 'Staged', 'Planned', 'Done', 'Declined']
def available():
return store.available()
def items(fresh=True):
"""All submissions, newest first. Lenient read (display only)."""
data = store.get(KEY, fresh=fresh) or {}
out = list(data.get('items', []))
out.sort(key=lambda r: r.get('ts', ''), reverse=True)
return out
def add(user, name, ftype, module, title, details, importance):
"""Append one submission (strict read-modify-write β€” a transient read error aborts,
never clobbers). Returns the new id."""
rec = {
'id': f'fb-{int(time.time() * 1000)}-{user}',
'ts': dt.datetime.now().strftime('%Y-%m-%d %H:%M'),
'user': user, 'name': name,
'type': ftype, 'module': module,
'title': (title or '').strip(),
'details': (details or '').strip(),
'importance': importance,
'status': 'New', 'note': '',
}
store.update(KEY, lambda d: {**d, 'items': d.get('items', []) + [rec]})
return rec['id']
def set_fields(fid, **fields):
"""Update triage fields (status / note) on one submission by id."""
def _fn(d):
for it in d.get('items', []):
if it.get('id') == fid:
it.update(fields)
return d
store.update(KEY, _fn)
def counts(rows=None):
"""Status -> count, for the header KPIs."""
rows = items() if rows is None else rows
out = {s: 0 for s in STATUSES}
for r in rows:
out[r.get('status', 'New')] = out.get(r.get('status', 'New'), 0) + 1
return out