Refactor .gitignore; add patterns for SQLite database files and improve ignored file management

Enhance app initialization; set secret key from environment variable for better security practices

Update work_log model import; change User import path for improved module structure

Refactor routes; add new inventory item creation route and enhance settings handling with JSON form state

Improve ComboBoxWidget; add handleComboAdd function for better option management and integrate with render_combobox macro

Revamp settings template; implement form state management and improve modal functionality for room creation

Add error template; create a new error handling page for better user feedback
This commit is contained in:
Yaro Kasear 2025-06-23 10:05:31 -05:00
parent 142e909a88
commit c6fc1a4795
9 changed files with 269 additions and 113 deletions

9
templates/error.html Normal file
View file

@ -0,0 +1,9 @@
{% extends 'layout.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="alert alert-danger text-center">
{{ message }}
</div>
{% endblock %}

View file

@ -21,13 +21,19 @@
</select>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
ComboBoxWidget.initComboBox("{{ id }}", {
{% if onAdd %}onAdd: function(newItem, list, createOption) { {{ onAdd | safe }} },{% endif %}
{% if onRemove %}onRemove: function(option) { {{ onRemove | safe }} },{% endif %}
{% if onEdit %}onEdit: function(option) { {{ onEdit | safe }} }{% endif %}
});
<script>
document.addEventListener('DOMContentLoaded', () => {
ComboBoxWidget.initComboBox("{{ id }}", {
onAdd: function(newItem, list, createOption) {
{% if onAdd %}
{{ onAdd | safe }}
{% else %}
ComboBoxWidget.handleComboAdd('{{ id }}-input', '{{ id }}-list', '{{ id }}s', '{{ label or id }}');
{% endif %}
},
{% if onRemove %}onRemove: function(option) { {{ onRemove | safe }} },{% endif %}
{% if onEdit %}onEdit: function(option) { {{ onEdit | safe }} }{% endif %}
});
</script>
});
</script>
{% endmacro %}

View file

@ -4,7 +4,9 @@
{% block content %}
<form method="POST" action="{{ url_for('main.settings') }}">
<form method="POST" id="settingsForm" action="{{ url_for('main.settings') }}">
<input type="hidden" name="formState" id="formStateField">
{{ breadcrumbs.breadcrumb_header(
title=title,
submit_button=True
@ -42,18 +44,18 @@
<div class="row">
<div class="col">
{{ combos.render_combobox(
id='section',
options=sections,
label='Sections',
placeholder='Add a new section'
id='section',
options=sections,
label='Sections',
placeholder='Add a new section'
) }}
</div>
<div class="col">
{{ combos.render_combobox(
id='function',
options=functions,
label='Functions',
placeholder='Add a new function'
id='function',
options=functions,
label='Functions',
placeholder='Add a new function'
) }}
</div>
</div>
@ -67,11 +69,11 @@
{% endset %}
<div class="col">
{{ combos.render_combobox(
id='room',
options=rooms,
label='Rooms',
placeholder='Add a new room',
onAdd=room_editor
id='room',
options=rooms,
label='Rooms',
placeholder='Add a new room',
onAdd=room_editor
) }}
</div>
</div>
@ -88,24 +90,24 @@
<div class="row">
<div class="col">
<label for="roomName" class="form-label">Room Name</label>
<input type="text" class="form-input" name="roomName" id="roomName"
<input type="text" class="form-input" id="roomName"
placeholder="Enter room name">
</div>
</div>
<div class="row">
<div class="col">
<label for="roomSection" class="form-label">Section</label>
<select name="roomSection" id="roomSection" class="form-select">
<option>Select a section</option>
<select id="roomSection" class="form-select">
<option value="">Select a section</option>
{% for section in sections %}
<option value="{{ section.id }}">{{ section.name }}</option>
{% endfor %}
</select>
</div>
<div class="col">
<label for="roomFunction" class="form-label">Function</label>
<select name="roomFunction" id="roomFunction" class="form-select">
<option>Select a function</option>
<label class="form-label">Function</label>
<select id="roomFunction" class="form-select">
<option value="">Select a function</option>
{% for function in functions %}
<option value="{{ function.id }}">{{ function.name }}</option>
{% endfor %}
@ -125,33 +127,82 @@
{% endblock %}
{% block script %}
const formState = {
brands: [],
types: [],
sections: [],
functions: [],
rooms: []
};
document.addEventListener('DOMContentLoaded', () => {
const modal = document.getElementById('roomEditor');
const saveButton = document.getElementById('roomEditorSaveButton');
const cancelButton = document.getElementById('roomEditorCancelButton');
const form = document.getElementById('settingsForm');
// Replace the whole submission logic with just JSON
form.addEventListener('submit', () => {
document.getElementById('formStateField').value = JSON.stringify(formState);
});
// Modal populates dropdowns fresh from the page every time it opens
modal.addEventListener('show.bs.modal', () => {
const modalSections = document.getElementById('roomSection');
const modalFunctions = document.getElementById('roomFunction');
const pageSections = document.getElementById('section-list');
const pageFunctions = document.getElementById('function-list');
modalSections.innerHTML = '';
modalFunctions.innerHTML = '';
modalSections.appendChild(new Option("Select a section", ""));
modalFunctions.appendChild(new Option("Select a function", ""));
Array.from(pageSections.options).forEach(opt =>
modalSections.appendChild(new Option(opt.textContent, opt.value))
);
Array.from(pageFunctions.options).forEach(opt =>
modalFunctions.appendChild(new Option(opt.textContent, opt.value))
);
});
saveButton.addEventListener('click', () => {
console.log('Save button clicked');
const name = document.getElementById('roomName').value;
const name = document.getElementById('roomName').value.trim();
const section = document.getElementById('roomSection').value;
const func = document.getElementById('roomFunction').value;
if (name.trim()) {
const newRoom = ComboBoxWidget.createOption(`${name}`, null);
const selectWidget = document.getElementById('room-list');
selectWidget.appendChild(newRoom);
ComboBoxWidget.sortOptions(selectWidget);
bootstrap.Modal.getInstance(modal).hide();
} else {
if (!name) {
alert('Please enter a room name.');
return;
}
// Avoid duplicate visible names
const roomList = document.getElementById('room-list');
const exists = Array.from(roomList.options).some(opt => opt.textContent.trim() === name);
if (exists) {
alert(`Room "${name}" already exists.`);
return;
}
// Add to select box visibly
const option = ComboBoxWidget.createOption(name);
roomList.appendChild(option);
ComboBoxWidget.sortOptions(roomList);
// Track in state object
formState.rooms.push({
name,
section_id: section,
function_id: func
});
bootstrap.Modal.getInstance(modal).hide();
});
cancelButton.addEventListener('click', () => {
console.log('Cancel button clicked');
bootstrap.Modal.getInstance(modal).hide();
});
});
{% endblock %}
{% endblock %}