Creation logic!

This commit is contained in:
Yaro Kasear 2025-10-03 13:43:23 -05:00
parent 2502375d32
commit 21a3399ecd
6 changed files with 45 additions and 10 deletions

View file

@ -653,9 +653,13 @@ class CRUDService(Generic[T]):
session = self.session
obj = self.model(**data)
session.add(obj)
session.flush()
self._log_version("create", obj, actor, commit=commit)
if commit:
session.commit()
self._log_version("create", obj, actor, commit=commit)
return obj
def update(self, id: int, data: dict, actor=None, *, commit: bool = True) -> T:

View file

@ -2,7 +2,7 @@ from typing import List, Optional
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Unicode, case, cast, func
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import Mapped, mapped_column, relationship, synonym
from sqlalchemy.sql import expression as sql
from crudkit.core.base import Base, CRUDMixin
@ -21,13 +21,14 @@ class Inventory(Base, CRUDMixin):
model: Mapped[Optional[str]] = mapped_column(Unicode(255))
notes: Mapped[Optional[str]] = mapped_column(Unicode(255))
shared: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sql.false())
timestamp: Mapped[DateTime] = mapped_column(DateTime)
timestamp: Mapped[DateTime] = mapped_column(DateTime, default=func.now(), nullable=False)
brand: Mapped[Optional['Brand']] = relationship('Brand', back_populates='inventory')
brand_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('brand.id'), nullable=True, index=True)
device_type: Mapped[Optional['DeviceType']] = relationship('DeviceType', back_populates='inventory')
type_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("item.id"), nullable=True, index=True)
device_type_id = synonym("type_id")
image: Mapped[Optional['Image']] = relationship('Image', back_populates='inventory', passive_deletes=True)
image_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('images.id', ondelete='SET NULL'), nullable=True, index=True)

View file

@ -240,6 +240,14 @@ def init_entry_routes(app):
updates = payload.pop("updates", []) or []
payload.pop("delete_update_ids", None) # irrelevant on create
if model == "inventory":
if "device_type_id" in payload and "type_id" not in payload:
payload["type_id"] = payload.pop("device_type_id")
for k in ("brand_id", "type_id", "owner_id", "location_id", "image_id"):
if payload.get(k) == "":
payload[k] = None
# payload["timestamp"] = datetime.now()
if model == "worklog":
if "contact" in payload and "contact_id" not in payload:
payload["contact_id"] = payload.pop("contact")
@ -279,7 +287,28 @@ def init_entry_routes(app):
params = {}
if model == "inventory":
pass
if "device_type_id" in payload:
payload["type_id"] = payload.pop("device_type_id")
for k in ("brand_id", "type_id", "owner_id", "location_id", "image_id"):
if payload.get(k) == "":
payload[k] = None
params = {
"fields": [
"barcode",
"name",
"serial",
"condition",
"model",
"notes",
"shared",
"timestamp",
"brand_id",
"type_id",
"image_id",
"location_id",
"owner_id",
]
}
elif model == "user":
params = {
"fields": [

View file

@ -1,7 +1,7 @@
<label class="form-label">Notes</label>
<div class="d-flex justify-content-between align-items-start">
<div class="me-3 w-100 markdown-body" id="editContainer"></div>
<script type="application/json" id="noteContent">{{ field['template_ctx']['values']['notes'] | tojson }}</script>
<script type="application/json" id="noteContent">{{ (field['template_ctx']['values']['notes'] if field['template_ctx']['values']['notes'] else '') | tojson }}</script>
<div class="form-check form-switch">
<input type="checkbox" class="form-check-input" id="editSwitch" onchange="changeMode()" role="switch"
aria-label="Edit mode switch for inventory notes.">
@ -20,7 +20,7 @@
}
@supports (field-sizing: content) {
text-area.auto-md {
textarea.auto-md {
field-sizing: content;
}
}
@ -35,7 +35,7 @@
function getMarkdown() {
const el = document.getElementById('noteContent');
return el ? JSON.parse(el.textContent) : "";
return el ? (JSON.parse(el.textContent) || "") : "";
}
function setMarkdown(md) {

View file

@ -63,7 +63,8 @@
const json = formToJson(formEl);
if (model === 'inventory' && typeof getMarkdown === 'function') {
json.notes = getMarkdown().trim();
const md = getMarkdown();
json.notes = (typeof md === 'string') ? getMarkdown().trim() : '';
} else if (model === 'worklog') {
json.updates = collectEditedUpdates();
json.delete_update_ids = collectDeletedIds();
@ -85,7 +86,7 @@
window.newDrafts = [];
window.deletedIds = [];
if (!hasId && reply.id) {
window.location.href = `/entry/${model}/${reply.id}?pretty=1`;
window.location.href = `/entry/${model}/${reply.id}`;
}
} else {
toastMessage(`Unable to save entry: ${reply.error}`, 'danger');

View file

@ -36,7 +36,7 @@
}
@supports (field-sizing: content) {
text-area.auto-md {
textarea.auto-md {
field-sizing: content;
}
}