Enhance settings page; integrate combo box widgets for brands, types, sections, and functions, and add pencil icon for editing functionality

This commit is contained in:
Yaro Kasear 2025-06-18 14:13:16 -05:00
parent dba2438937
commit ad413c3f1b
6 changed files with 177 additions and 67 deletions

View file

@ -0,0 +1,29 @@
{% import "fragments/_icon_fragment.html" as icons %}
{% macro render_combobox(id, options, label=none, placeholder=none) %}
{% if label %}
<label for="{{ id }}-input" class="form-label">{{ label }}</label>
{% endif %}
<div class="combo-box-widget" id="{{ id }}-container">
<div class="input-group">
<input type="text" class="form-control rounded-bottom-0" id="{{ id }}-input"{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}>
<button type="button" class="btn btn-primary rounded-bottom-0" id="{{ id }}-add" disabled>
{{ icons.plus(16) }}
</button>
<button type="button" class="btn btn-danger rounded-bottom-0" id="{{ id }}-remove" disabled>
{{ icons.minus(16) }}
</button>
</div>
<select class="form-select border-top-0 rounded-top-0" id="{{ id }}-list" name="{{ id }}" size="10" multiple>
{% for option in options %}
<option value="{{ option.id }}">{{ option.name }}</option>
{% endfor %}
</select>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
ComboBoxWidget.initComboBox("{{ id }}");
});
</script>
{% endmacro %}

View file

@ -77,6 +77,14 @@
</svg>
{% endmacro %}
{% macro pencil(size=24) %}
<svg xmlns="http://www.w3.org/2000/svg" width="{{ size }}" height="{{ size }}" fill="currentColor"
class="bi bi-pencil align-self-center" viewBox="0 0 16 16">
<path
d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325" />
</svg>
{% endmacro %}
{% macro plus(size=24) %}
<svg xmlns="http://www.w3.org/2000/svg" width="{{ size }}" height="{{ size }}" fill="currentColor"
class="bi bi-plus-lg align-self-center" viewBox="0 0 16 16">

View file

@ -1,4 +1,5 @@
{% import "fragments/_breadcrumb_fragment.html" as breadcrumbs %}
{% import "fragments/_combobox_fragment.html" as combos %}
{% import "fragments/_icon_fragment.html" as icons %}
{% import "fragments/_link_fragment.html" as links %}
{% import "fragments/_table_fragment.html" as tables %}
@ -20,6 +21,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/widget.css') }}">
<style>
{% block style %}
{% endblock %}
</style>
</head>
@ -62,6 +64,7 @@
src="https://cdn.datatables.net/v/bs5/jq-3.7.0/moment-2.29.4/dt-2.3.2/b-3.2.3/b-colvis-3.2.3/b-print-3.2.3/cr-2.1.1/cc-1.0.4/r-3.0.4/rg-1.5.1/rr-1.5.0/sc-2.4.3/sr-1.4.1/datatables.min.js"
integrity="sha384-tNYRX2RiDDDRKCJgPF8Pw3rTxC1GUe1pt5qH1SBmwcazrEUj7Ii4C1Tz9wCCRUI4"
crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='js/widget.js') }}"></script>
<script>
const searchInput = document.querySelector('#search');
const searchButton = document.querySelector('#searchButton');

View file

@ -5,81 +5,67 @@
{% block content %}
<form method="POST" action="{{ url_for('main.settings') }}">
{{ breadcrumbs.breadcrumb_header(
{{ breadcrumbs.breadcrumb_header(
title=title,
submit_button=True
) }}
) }}
<div class="container">
<label for="brandInput" class="form-label">Brands</label>
<div class="combo-box-widget">
<div class="input-group">
<input type="text" class="form-control rounded-bottom-0" id="brandInput" name="brandInput" placeholder="Add a new brand">
<button type="button" class="btn btn-primary rounded-bottom-0" id="addBrandButton" onclick="SettingsPage.addBrand();" disabled>
{{ icons.plus(16) }}
</button>
<button type="button" class="btn btn-danger rounded-bottom-0" id="removeBrandButton" onclick="SettingsPage.removeSelectedBrands()" disabled>
{{ icons.minus(16) }}
</button>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">
Inventory Settings
</h5>
<div class="row">
<div class="col">
{{ combos.render_combobox(
id='brand',
options=brands,
label='Brands',
placeholder='Add a new brand'
) }}
</div>
<div class="col">
{{ combos.render_combobox(
id='type',
options=types,
label='Inventory Types',
placeholder='Add a new type'
) }}
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">Location Settings</h5>
<div class="row">
<div class="col">
{{ combos.render_combobox(
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'
) }}
</div>
</div>
</div>
<select class="form-select border-top-0 rounded-top-0" id="brandList" size="10" multiple>
{% for brand in brands %}
<option value="{{ brand.id }}">{{ brand.name }}</option>
{% endfor %}
</select>
</div>
</div>
</form>
{% endblock %}
{% block script %}
const SettingsPage = (() => {
const brandInput = document.querySelector('#brandInput');
const brandList = document.querySelector('#brandList');
const addBrandButton = document.querySelector('#addBrandButton');
const removeBrandButton = document.querySelector('#removeBrandButton');
let tempIdCounter = -1;
function init() {
brandInput.addEventListener('input', () => {
addBrandButton.disabled = brandInput.value.trim() === '';
});
brandList.addEventListener('change', () => {
removeBrandButton.disabled = brandList.selectedOptions.length === 0;
});
}
function addBrand() {
const newBrand = brandInput.value.trim();
if (newBrand) {
const option = document.createElement('option');
option.textContent = newBrand;
option.value = tempIdCounter--;
brandList.appendChild(option);
brandInput.value = '';
addBrandButton.disabled = true;
sortOptions();
}
}
function removeSelectedBrands() {
Array.from(brandList.selectedOptions).forEach(option => option.remove());
removeBrandButton.disabled = true;
}
function sortOptions() {
Array.from(brandList.options)
.sort((a, b) => a.text.localeCompare(b.text))
.forEach(option => brandList.appendChild(option));
}
return {
init,
addBrand,
removeSelectedBrands
const icons = {
add: `{{ icons.plus(16)|safe }}`,
edit: `{{ icons.pencil(16)|safe }}`,
};
})();
document.addEventListener('DOMContentLoaded', SettingsPage.init);
{% endblock %}