Adding logic to add updates.

This commit is contained in:
Yaro Kasear 2025-10-07 10:56:00 -05:00
parent 53cc90a74b
commit 598a9f7793
2 changed files with 56 additions and 21 deletions

View file

@ -274,7 +274,6 @@ def init_entry_routes(app):
for k in ("brand_id", "type_id", "owner_id", "location_id", "image_id"): for k in ("brand_id", "type_id", "owner_id", "location_id", "image_id"):
if payload.get(k) == "": if payload.get(k) == "":
payload[k] = None payload[k] = None
# payload["timestamp"] = datetime.now()
if model == "worklog": if model == "worklog":
if "contact" in payload and "contact_id" not in payload: if "contact" in payload and "contact_id" not in payload:
@ -285,13 +284,17 @@ def init_entry_routes(app):
# Parent first, no commit yet # Parent first, no commit yet
obj = svc.create(payload, actor="create_entry", commit=False) obj = svc.create(payload, actor="create_entry", commit=False)
# Ensure PK is available for children and relationship auto-FK works
sess.flush()
# Children # Children
if model == "worklog" and updates: if model == "worklog" and updates:
note_cls = type(obj).updates.property.mapper.class_ note_mapper = type(obj).updates.property.mapper
note_cls = note_mapper.class_
for item in updates: for item in updates:
content = (item.get("content") or "").trim() if hasattr(str, 'trim') else (item.get("content") or "").strip() content = (item.get("content") or "").strip()
if content: if content:
sess.add(note_cls(work_log_id=obj.id, content=content)) obj.updates.append(note_cls(content=content))
sess.commit() sess.commit()
return {"status": "success", "id": obj.id} return {"status": "success", "id": obj.id}

View file

@ -14,7 +14,8 @@
</small> </small>
</div> </div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="editSwitch{{ n.id }}" onchange="changeMode({{ n.id }})" role="switch" aria-label="Edit mode for update {{ n.id }}"> <input class="form-check-input" type="checkbox" id="editSwitch{{ n.id }}" onchange="changeMode({{ n.id }})"
role="switch" aria-label="Edit mode for update {{ n.id }}">
<label for="editSwitch{{ n.id }}" class="form-check-label">Edit</label> <label for="editSwitch{{ n.id }}" class="form-check-label">Edit</label>
</div> </div>
</div> </div>
@ -25,30 +26,61 @@
{% endfor %} {% endfor %}
</ul> </ul>
<div class="mt-3">
<label class="form-label">Add update</label>
<textarea id="newUpdateInput" class="form-control auto-md" rows="3" placeholder="Write a new update..."></textarea>
<div class="mt-2 d-flex gap-2">
<button type="button" class="btn btn-primary btn-sm" onclick="addNewDraft()">Add</button>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="clearNewDraft()">Clear</button>
</div>
<div id="newDraftsList" class="mt-3 d-none">
<div class="fw-semibold mb-1">Pending new updates</div>
<ul class="list-group" id="newDraftsUl"></ul>
</div>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown.min.css">
<style> <style>
textarea.auto-md { textarea.auto-md {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
max-height: 60vh; max-height: 60vh;
overflow: hidden; overflow: hidden;
resize: vertical; resize: vertical;
} }
@supports (field-sizing: content) { @supports (field-sizing: content) {
textarea.auto-md { textarea.auto-md {
field-sizing: content; field-sizing: content;
}
} }
}
</style> </style>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
<script> <script>
window.newDrafts = window.newDrafts || [];
window.deletedIds = window.deletedIds || [];
function addNewDraft() {
const ta = document.getElementById('newUpdateInput');
const text = (ta.value || '').trim()
if (!text) return;
window.newDrafts.push(text);
ta.value = '';
renderNewDrafts();
}
function clearNewDraft() {
const ta = document.getElementById('newUpdateInput');
ta.value = '';
}
// Initial render // Initial render
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const ids = [ {% for n in items %} {{ n.id }}{% if not loop.last %}, {% endif %}{% endfor %} ]; const ids = [{% for n in items %} {{ n.id }}{% if not loop.last %}, {% endif %} {% endfor %} ];
for (const id of ids) renderView(id, getMarkdown(id)); for (const id of ids) renderView(id, getMarkdown(id));
}); });
function getMarkdown(id) { function getMarkdown(id) {
@ -64,7 +96,7 @@
const container = document.getElementById(`editContainer${id}`); const container = document.getElementById(`editContainer${id}`);
if (!container) return; if (!container) return;
const html = marked.parse(md || ""); const html = marked.parse(md || "");
container.innerHTML = DOMPurify.sanitize(html, { ADD_ATTR: ['target','rel'] }); container.innerHTML = DOMPurify.sanitize(html, { ADD_ATTR: ['target', 'rel'] });
for (const a of container.querySelectorAll('a[href]')) { for (const a of container.querySelectorAll('a[href]')) {
a.setAttribute('target', '_blank'); a.setAttribute('target', '_blank');
a.setAttribute('rel', 'noopener noreferrer nofollow'); a.setAttribute('rel', 'noopener noreferrer nofollow');
@ -121,6 +153,6 @@
} }
function escapeForTextarea(s) { function escapeForTextarea(s) {
return (s ?? "").replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); return (s ?? "").replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
} }
</script> </script>