v1.0.1: Add form history with unique ID support

New features:
- unique_id_fields in YAML config to define form identity
- Form selector dropdown to switch between saved forms
- Multiple forms can be saved per device
- Auto-detect existing forms when filling ID fields
- Delete saved forms functionality
- Forms persist in localStorage with index

Changes:
- yaml_parser.py: Added unique_id_fields support
- generator.py: Added form selector UI
- templates.py: Complete rewrite of save/load logic for multi-form support
- config.yaml: Example with serienummer and asset_id as unique fields
v1.0.1
killercow 2 weeks ago
parent 20e0720ffe
commit cfd852cbc3

@ -1,8 +1,8 @@
# Machine Inventarisatie - Voorbeeld Configuratie
# EasySmartInventory v1.0.0
# EasySmartInventory v1.0.1
name: "Machine_Inventarisatie"
version: "1.0.0"
version: "1.0.1"
# Styling configuratie
style:
@ -35,6 +35,13 @@ autosave:
use_url_hash: true
use_localstorage: true
# Unieke identificatie voor formulieren
# Deze velden bepalen samen het unieke ID voor opgeslagen formulieren
# Hiermee kunnen meerdere formulieren op hetzelfde apparaat worden opgeslagen
unique_id_fields:
- "serienummer"
- "asset_id"
# Secties en velden
sections:
- name: "Basisinformatie"

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="EasySmartInventory v1.0.0">
<meta name="generator" content="EasySmartInventory v1.0.1">
<title>Machine_Inventarisatie</title>
<style>
@ -287,6 +287,43 @@ input.invalid, select.invalid, textarea.invalid {
.photo-container.has-photo .photo-preview { display: block !important; }
.photo-container.has-photo .photo-buttons { display: flex !important; }
.form-selector-container {
padding: 15px 30px;
background: linear-gradient(to right, #f8f9fa, #e9ecef);
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.form-selector-container label {
font-weight: 600;
margin: 0;
white-space: nowrap;
}
.form-selector-container select {
flex: 1;
min-width: 200px;
max-width: 400px;
}
.form-selector-container .btn {
padding: 8px 16px;
font-size: 0.9em;
}
@media (max-width: 768px) {
.form-selector-container {
flex-direction: column;
align-items: stretch;
}
.form-selector-container select {
max-width: 100%;
}
}
</style>
</head>
<body>
@ -294,9 +331,17 @@ input.invalid, select.invalid, textarea.invalid {
<header>
<h1>Machine_Inventarisatie</h1>
<div class="version">Versie 1.0.0</div>
<div class="version">Versie 1.0.1</div>
</header>
<div class="form-selector-container">
<label for="form-selector">📋 Opgeslagen formulieren:</label>
<select id="form-selector">
<option value="">-- Selecteer --</option>
</select>
<button type="button" class="btn btn-danger" onclick="deleteForm()">🗑️ Verwijder</button>
</div>
<form id="inventory-form" onsubmit="return false;">
<section class="section">
<h2>Basisinformatie</h2>
@ -613,14 +658,14 @@ input.invalid, select.invalid, textarea.invalid {
<div class="actions">
<button type="button" class="btn btn-primary" onclick="exportCSV()">📥 Exporteer CSV</button>
<button type="button" class="btn btn-success" onclick="sendEmail(this)">📧 Verstuur per Email</button>
<button type="button" class="btn btn-danger" onclick="clearForm()">🗑️ Formulier Wissen</button>
<button type="button" class="btn btn-secondary" onclick="clearForm()">🔄 Nieuw Formulier</button>
</div>
</form>
<div class="status-bar">
<span id="save-indicator" class="save-indicator">Gereed</span>
<span>EasySmartInventory v1.0.0</span>
<span>EasySmartInventory v1.0.1</span>
</div>
</div>
@ -631,13 +676,15 @@ input.invalid, select.invalid, textarea.invalid {
(function() {
'use strict';
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.0", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}};
const STORAGE_KEY = 'inventory_' + CONFIG.name + '_' + CONFIG.version;
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.1", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}, "unique_id_fields": ["serienummer", "asset_id"]};
const FORMS_INDEX_KEY = 'inventory_' + CONFIG.name + '_forms_index';
let currentFormId = null;
let saveTimeout = null;
let hasChanges = false;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
setupFormSelector();
loadSavedData();
setupAutoSave();
setupValidation();
@ -645,6 +692,173 @@ input.invalid, select.invalid, textarea.invalid {
updateSaveIndicator('loaded');
});
// Get unique form ID based on configured fields
function getFormUniqueId() {
if (!CONFIG.unique_id_fields || CONFIG.unique_id_fields.length === 0) {
return 'default';
}
const parts = [];
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value && field.value.trim()) {
parts.push(field.value.trim());
}
});
return parts.length > 0 ? parts.join('_') : null;
}
// Get storage key for a specific form
function getStorageKey(formId) {
return 'inventory_' + CONFIG.name + '_' + CONFIG.version + '_form_' + formId;
}
// Get all saved forms from index
function getSavedForms() {
try {
const index = localStorage.getItem(FORMS_INDEX_KEY);
return index ? JSON.parse(index) : [];
} catch (e) {
return [];
}
}
// Save form to index
function saveFormToIndex(formId, label) {
const forms = getSavedForms();
const existing = forms.findIndex(f => f.id === formId);
const formInfo = {
id: formId,
label: label || formId,
lastModified: new Date().toISOString()
};
if (existing >= 0) {
forms[existing] = formInfo;
} else {
forms.push(formInfo);
}
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
updateFormSelector();
}
// Remove form from index
function removeFormFromIndex(formId) {
const forms = getSavedForms().filter(f => f.id !== formId);
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
localStorage.removeItem(getStorageKey(formId));
updateFormSelector();
}
// Setup form selector dropdown
function setupFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
updateFormSelector();
selector.addEventListener('change', function() {
const selectedId = this.value;
if (selectedId === '__new__') {
clearFormData();
currentFormId = null;
showToast('Nieuw formulier gestart', 'success');
} else if (selectedId) {
loadFormById(selectedId);
}
});
// Watch unique ID fields for changes
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field) {
field.addEventListener('blur', function() {
const newId = getFormUniqueId();
if (newId && newId !== currentFormId) {
// Check if this form already exists
const existing = getSavedForms().find(f => f.id === newId);
if (existing) {
if (confirm('Er bestaat al een formulier met deze ID. Wilt u dit formulier laden?')) {
loadFormById(newId);
}
}
}
});
}
});
}
}
// Update form selector options
function updateFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
const forms = getSavedForms();
const currentValue = selector.value;
// Clear and rebuild
selector.innerHTML = '<option value="">-- Selecteer opgeslagen formulier --</option>';
selector.innerHTML += '<option value="__new__"> Nieuw formulier</option>';
if (forms.length > 0) {
const optgroup = document.createElement('optgroup');
optgroup.label = 'Opgeslagen formulieren (' + forms.length + ')';
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
forms.forEach(form => {
const option = document.createElement('option');
option.value = form.id;
const date = new Date(form.lastModified).toLocaleString('nl-NL');
option.textContent = form.label + ' (' + date + ')';
if (form.id === currentFormId) {
option.selected = true;
}
optgroup.appendChild(option);
});
selector.appendChild(optgroup);
}
}
// Load a specific form by ID
function loadFormById(formId) {
try {
const saved = localStorage.getItem(getStorageKey(formId));
if (saved) {
clearFormData();
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
currentFormId = formId;
updateFormSelector();
showToast('Formulier geladen: ' + formId, 'success');
}
} catch (e) {
console.warn('Could not load form:', e);
showToast('Kon formulier niet laden', 'error');
}
}
// Clear form data (without removing from storage)
function clearFormData() {
document.querySelectorAll('input[type="text"], input[type="number"], input[type="date"], select, textarea').forEach(field => {
field.value = '';
field.classList.remove('invalid');
});
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
document.querySelectorAll('.photo-preview').forEach(img => {
img.src = '';
img.style.display = 'none';
img.parentElement.classList.remove('has-photo');
});
history.replaceState(null, '', window.location.pathname);
}
// Load saved data from localStorage or URL
function loadSavedData() {
// Try URL hash first
@ -655,24 +869,20 @@ input.invalid, select.invalid, textarea.invalid {
params.forEach((value, key) => {
setFieldValue(key, value);
});
currentFormId = getFormUniqueId();
return;
} catch (e) {
console.warn('Could not parse URL hash:', e);
}
}
// Try localStorage
// Try to load most recent form from localStorage
if (CONFIG.autosave.use_localstorage) {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
}
} catch (e) {
console.warn('Could not load from localStorage:', e);
const forms = getSavedForms();
if (forms.length > 0) {
// Load most recent
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
loadFormById(forms[0].id);
}
}
}
@ -741,11 +951,33 @@ input.invalid, select.invalid, textarea.invalid {
// Save data
function saveData() {
const data = getFormData();
const formId = getFormUniqueId();
// Only save if we have a valid form ID
if (!formId) {
updateSaveIndicator('waiting');
return;
}
// Save to localStorage
// Save to localStorage with form-specific key
if (CONFIG.autosave.use_localstorage) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
localStorage.setItem(getStorageKey(formId), JSON.stringify(data));
// Build label from unique ID fields
const labelParts = [];
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value) {
labelParts.push(field.value);
}
});
}
const label = labelParts.join(' - ') || formId;
saveFormToIndex(formId, label);
currentFormId = formId;
} catch (e) {
console.warn('Could not save to localStorage:', e);
}
@ -802,7 +1034,8 @@ input.invalid, select.invalid, textarea.invalid {
const statusText = {
'loaded': 'Gegevens geladen',
'saving': 'Opslaan...',
'saved': 'Opgeslagen ✓'
'saved': 'Opgeslagen ✓',
'waiting': 'Vul ID-velden in om op te slaan'
};
indicator.textContent = statusText[status] || status;
@ -1101,12 +1334,32 @@ input.invalid, select.invalid, textarea.invalid {
img.parentElement.classList.remove('has-photo');
});
localStorage.removeItem(STORAGE_KEY);
history.replaceState(null, '', window.location.pathname);
currentFormId = null;
updateFormSelector();
showToast('Formulier gewist', 'success');
};
// Delete saved form
window.deleteForm = function() {
if (!currentFormId) {
showToast('Geen formulier geselecteerd om te verwijderen', 'error');
return;
}
if (!confirm('Weet u zeker dat u dit opgeslagen formulier wilt verwijderen?\n\nFormulier: ' + currentFormId)) {
return;
}
removeFormFromIndex(currentFormId);
clearFormData();
currentFormId = null;
updateFormSelector();
showToast('Formulier verwijderd', 'success');
};
// Show toast notification
function showToast(message, type) {
const toast = document.getElementById('toast');

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="EasySmartInventory v1.0.0">
<meta name="generator" content="EasySmartInventory v1.0.1">
<title>Machine_Inventarisatie</title>
<style>
@ -318,6 +318,43 @@ select {
.photo-container.has-photo .photo-preview { display: block !important; }
.photo-container.has-photo .photo-buttons { display: flex !important; }
.form-selector-container {
padding: 15px 30px;
background: linear-gradient(to right, #f8f9fa, #e9ecef);
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.form-selector-container label {
font-weight: 600;
margin: 0;
white-space: nowrap;
}
.form-selector-container select {
flex: 1;
min-width: 200px;
max-width: 400px;
}
.form-selector-container .btn {
padding: 8px 16px;
font-size: 0.9em;
}
@media (max-width: 768px) {
.form-selector-container {
flex-direction: column;
align-items: stretch;
}
.form-selector-container select {
max-width: 100%;
}
}
</style>
</head>
<body>
@ -325,9 +362,17 @@ select {
<header>
<h1>Machine_Inventarisatie</h1>
<div class="version">Versie 1.0.0</div>
<div class="version">Versie 1.0.1</div>
</header>
<div class="form-selector-container">
<label for="form-selector">📋 Opgeslagen formulieren:</label>
<select id="form-selector">
<option value="">-- Selecteer --</option>
</select>
<button type="button" class="btn btn-danger" onclick="deleteForm()">🗑️ Verwijder</button>
</div>
<form id="inventory-form" onsubmit="return false;">
<section class="section">
<h2>Basisinformatie</h2>
@ -644,14 +689,14 @@ select {
<div class="actions">
<button type="button" class="btn btn-primary" onclick="exportCSV()">📥 Exporteer CSV</button>
<button type="button" class="btn btn-success" onclick="sendEmail(this)">📧 Verstuur per Email</button>
<button type="button" class="btn btn-danger" onclick="clearForm()">🗑️ Formulier Wissen</button>
<button type="button" class="btn btn-secondary" onclick="clearForm()">🔄 Nieuw Formulier</button>
</div>
</form>
<div class="status-bar">
<span id="save-indicator" class="save-indicator">Gereed</span>
<span>EasySmartInventory v1.0.0</span>
<span>EasySmartInventory v1.0.1</span>
</div>
</div>
@ -662,13 +707,15 @@ select {
(function() {
'use strict';
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.0", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}};
const STORAGE_KEY = 'inventory_' + CONFIG.name + '_' + CONFIG.version;
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.1", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}, "unique_id_fields": ["serienummer", "asset_id"]};
const FORMS_INDEX_KEY = 'inventory_' + CONFIG.name + '_forms_index';
let currentFormId = null;
let saveTimeout = null;
let hasChanges = false;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
setupFormSelector();
loadSavedData();
setupAutoSave();
setupValidation();
@ -676,6 +723,173 @@ select {
updateSaveIndicator('loaded');
});
// Get unique form ID based on configured fields
function getFormUniqueId() {
if (!CONFIG.unique_id_fields || CONFIG.unique_id_fields.length === 0) {
return 'default';
}
const parts = [];
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value && field.value.trim()) {
parts.push(field.value.trim());
}
});
return parts.length > 0 ? parts.join('_') : null;
}
// Get storage key for a specific form
function getStorageKey(formId) {
return 'inventory_' + CONFIG.name + '_' + CONFIG.version + '_form_' + formId;
}
// Get all saved forms from index
function getSavedForms() {
try {
const index = localStorage.getItem(FORMS_INDEX_KEY);
return index ? JSON.parse(index) : [];
} catch (e) {
return [];
}
}
// Save form to index
function saveFormToIndex(formId, label) {
const forms = getSavedForms();
const existing = forms.findIndex(f => f.id === formId);
const formInfo = {
id: formId,
label: label || formId,
lastModified: new Date().toISOString()
};
if (existing >= 0) {
forms[existing] = formInfo;
} else {
forms.push(formInfo);
}
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
updateFormSelector();
}
// Remove form from index
function removeFormFromIndex(formId) {
const forms = getSavedForms().filter(f => f.id !== formId);
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
localStorage.removeItem(getStorageKey(formId));
updateFormSelector();
}
// Setup form selector dropdown
function setupFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
updateFormSelector();
selector.addEventListener('change', function() {
const selectedId = this.value;
if (selectedId === '__new__') {
clearFormData();
currentFormId = null;
showToast('Nieuw formulier gestart', 'success');
} else if (selectedId) {
loadFormById(selectedId);
}
});
// Watch unique ID fields for changes
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field) {
field.addEventListener('blur', function() {
const newId = getFormUniqueId();
if (newId && newId !== currentFormId) {
// Check if this form already exists
const existing = getSavedForms().find(f => f.id === newId);
if (existing) {
if (confirm('Er bestaat al een formulier met deze ID. Wilt u dit formulier laden?')) {
loadFormById(newId);
}
}
}
});
}
});
}
}
// Update form selector options
function updateFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
const forms = getSavedForms();
const currentValue = selector.value;
// Clear and rebuild
selector.innerHTML = '<option value="">-- Selecteer opgeslagen formulier --</option>';
selector.innerHTML += '<option value="__new__"> Nieuw formulier</option>';
if (forms.length > 0) {
const optgroup = document.createElement('optgroup');
optgroup.label = 'Opgeslagen formulieren (' + forms.length + ')';
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
forms.forEach(form => {
const option = document.createElement('option');
option.value = form.id;
const date = new Date(form.lastModified).toLocaleString('nl-NL');
option.textContent = form.label + ' (' + date + ')';
if (form.id === currentFormId) {
option.selected = true;
}
optgroup.appendChild(option);
});
selector.appendChild(optgroup);
}
}
// Load a specific form by ID
function loadFormById(formId) {
try {
const saved = localStorage.getItem(getStorageKey(formId));
if (saved) {
clearFormData();
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
currentFormId = formId;
updateFormSelector();
showToast('Formulier geladen: ' + formId, 'success');
}
} catch (e) {
console.warn('Could not load form:', e);
showToast('Kon formulier niet laden', 'error');
}
}
// Clear form data (without removing from storage)
function clearFormData() {
document.querySelectorAll('input[type="text"], input[type="number"], input[type="date"], select, textarea').forEach(field => {
field.value = '';
field.classList.remove('invalid');
});
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
document.querySelectorAll('.photo-preview').forEach(img => {
img.src = '';
img.style.display = 'none';
img.parentElement.classList.remove('has-photo');
});
history.replaceState(null, '', window.location.pathname);
}
// Load saved data from localStorage or URL
function loadSavedData() {
// Try URL hash first
@ -686,24 +900,20 @@ select {
params.forEach((value, key) => {
setFieldValue(key, value);
});
currentFormId = getFormUniqueId();
return;
} catch (e) {
console.warn('Could not parse URL hash:', e);
}
}
// Try localStorage
// Try to load most recent form from localStorage
if (CONFIG.autosave.use_localstorage) {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
}
} catch (e) {
console.warn('Could not load from localStorage:', e);
const forms = getSavedForms();
if (forms.length > 0) {
// Load most recent
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
loadFormById(forms[0].id);
}
}
}
@ -772,11 +982,33 @@ select {
// Save data
function saveData() {
const data = getFormData();
const formId = getFormUniqueId();
// Only save if we have a valid form ID
if (!formId) {
updateSaveIndicator('waiting');
return;
}
// Save to localStorage
// Save to localStorage with form-specific key
if (CONFIG.autosave.use_localstorage) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
localStorage.setItem(getStorageKey(formId), JSON.stringify(data));
// Build label from unique ID fields
const labelParts = [];
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value) {
labelParts.push(field.value);
}
});
}
const label = labelParts.join(' - ') || formId;
saveFormToIndex(formId, label);
currentFormId = formId;
} catch (e) {
console.warn('Could not save to localStorage:', e);
}
@ -833,7 +1065,8 @@ select {
const statusText = {
'loaded': 'Gegevens geladen',
'saving': 'Opslaan...',
'saved': 'Opgeslagen ✓'
'saved': 'Opgeslagen ✓',
'waiting': 'Vul ID-velden in om op te slaan'
};
indicator.textContent = statusText[status] || status;
@ -1132,12 +1365,32 @@ select {
img.parentElement.classList.remove('has-photo');
});
localStorage.removeItem(STORAGE_KEY);
history.replaceState(null, '', window.location.pathname);
currentFormId = null;
updateFormSelector();
showToast('Formulier gewist', 'success');
};
// Delete saved form
window.deleteForm = function() {
if (!currentFormId) {
showToast('Geen formulier geselecteerd om te verwijderen', 'error');
return;
}
if (!confirm('Weet u zeker dat u dit opgeslagen formulier wilt verwijderen?\n\nFormulier: ' + currentFormId)) {
return;
}
removeFormFromIndex(currentFormId);
clearFormData();
currentFormId = null;
updateFormSelector();
showToast('Formulier verwijderd', 'success');
};
// Show toast notification
function showToast(message, type) {
const toast = document.getElementById('toast');

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="EasySmartInventory v1.0.0">
<meta name="generator" content="EasySmartInventory v1.0.1">
<title>Machine_Inventarisatie</title>
<style>
@ -349,6 +349,43 @@ input.invalid, select.invalid, textarea.invalid {
.photo-container.has-photo .photo-preview { display: block !important; }
.photo-container.has-photo .photo-buttons { display: flex !important; }
.form-selector-container {
padding: 15px 30px;
background: linear-gradient(to right, #f8f9fa, #e9ecef);
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.form-selector-container label {
font-weight: 600;
margin: 0;
white-space: nowrap;
}
.form-selector-container select {
flex: 1;
min-width: 200px;
max-width: 400px;
}
.form-selector-container .btn {
padding: 8px 16px;
font-size: 0.9em;
}
@media (max-width: 768px) {
.form-selector-container {
flex-direction: column;
align-items: stretch;
}
.form-selector-container select {
max-width: 100%;
}
}
</style>
</head>
<body>
@ -356,9 +393,17 @@ input.invalid, select.invalid, textarea.invalid {
<header>
<h1>Machine_Inventarisatie</h1>
<div class="version">Versie 1.0.0</div>
<div class="version">Versie 1.0.1</div>
</header>
<div class="form-selector-container">
<label for="form-selector">📋 Opgeslagen formulieren:</label>
<select id="form-selector">
<option value="">-- Selecteer --</option>
</select>
<button type="button" class="btn btn-danger" onclick="deleteForm()">🗑️ Verwijder</button>
</div>
<form id="inventory-form" onsubmit="return false;">
<section class="section">
<h2>Basisinformatie</h2>
@ -675,14 +720,14 @@ input.invalid, select.invalid, textarea.invalid {
<div class="actions">
<button type="button" class="btn btn-primary" onclick="exportCSV()">📥 Exporteer CSV</button>
<button type="button" class="btn btn-success" onclick="sendEmail(this)">📧 Verstuur per Email</button>
<button type="button" class="btn btn-danger" onclick="clearForm()">🗑️ Formulier Wissen</button>
<button type="button" class="btn btn-secondary" onclick="clearForm()">🔄 Nieuw Formulier</button>
</div>
</form>
<div class="status-bar">
<span id="save-indicator" class="save-indicator">Gereed</span>
<span>EasySmartInventory v1.0.0</span>
<span>EasySmartInventory v1.0.1</span>
</div>
</div>
@ -693,13 +738,15 @@ input.invalid, select.invalid, textarea.invalid {
(function() {
'use strict';
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.0", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}};
const STORAGE_KEY = 'inventory_' + CONFIG.name + '_' + CONFIG.version;
const CONFIG = {"name": "Machine_Inventarisatie", "version": "1.0.1", "autosave": {"enabled": true, "interval_seconds": 5, "use_url_hash": true, "use_localstorage": true}, "export": {"csv": {"enabled": true, "include_photo": true}, "mailto": {"enabled": true, "to": "inventaris@bedrijf.nl", "subject_prefix": "Inventarisatie", "subject_fields": ["serienummer", "merk"], "include_timestamp": true}}, "unique_id_fields": ["serienummer", "asset_id"]};
const FORMS_INDEX_KEY = 'inventory_' + CONFIG.name + '_forms_index';
let currentFormId = null;
let saveTimeout = null;
let hasChanges = false;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
setupFormSelector();
loadSavedData();
setupAutoSave();
setupValidation();
@ -707,6 +754,173 @@ input.invalid, select.invalid, textarea.invalid {
updateSaveIndicator('loaded');
});
// Get unique form ID based on configured fields
function getFormUniqueId() {
if (!CONFIG.unique_id_fields || CONFIG.unique_id_fields.length === 0) {
return 'default';
}
const parts = [];
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value && field.value.trim()) {
parts.push(field.value.trim());
}
});
return parts.length > 0 ? parts.join('_') : null;
}
// Get storage key for a specific form
function getStorageKey(formId) {
return 'inventory_' + CONFIG.name + '_' + CONFIG.version + '_form_' + formId;
}
// Get all saved forms from index
function getSavedForms() {
try {
const index = localStorage.getItem(FORMS_INDEX_KEY);
return index ? JSON.parse(index) : [];
} catch (e) {
return [];
}
}
// Save form to index
function saveFormToIndex(formId, label) {
const forms = getSavedForms();
const existing = forms.findIndex(f => f.id === formId);
const formInfo = {
id: formId,
label: label || formId,
lastModified: new Date().toISOString()
};
if (existing >= 0) {
forms[existing] = formInfo;
} else {
forms.push(formInfo);
}
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
updateFormSelector();
}
// Remove form from index
function removeFormFromIndex(formId) {
const forms = getSavedForms().filter(f => f.id !== formId);
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
localStorage.removeItem(getStorageKey(formId));
updateFormSelector();
}
// Setup form selector dropdown
function setupFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
updateFormSelector();
selector.addEventListener('change', function() {
const selectedId = this.value;
if (selectedId === '__new__') {
clearFormData();
currentFormId = null;
showToast('Nieuw formulier gestart', 'success');
} else if (selectedId) {
loadFormById(selectedId);
}
});
// Watch unique ID fields for changes
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field) {
field.addEventListener('blur', function() {
const newId = getFormUniqueId();
if (newId && newId !== currentFormId) {
// Check if this form already exists
const existing = getSavedForms().find(f => f.id === newId);
if (existing) {
if (confirm('Er bestaat al een formulier met deze ID. Wilt u dit formulier laden?')) {
loadFormById(newId);
}
}
}
});
}
});
}
}
// Update form selector options
function updateFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
const forms = getSavedForms();
const currentValue = selector.value;
// Clear and rebuild
selector.innerHTML = '<option value="">-- Selecteer opgeslagen formulier --</option>';
selector.innerHTML += '<option value="__new__"> Nieuw formulier</option>';
if (forms.length > 0) {
const optgroup = document.createElement('optgroup');
optgroup.label = 'Opgeslagen formulieren (' + forms.length + ')';
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
forms.forEach(form => {
const option = document.createElement('option');
option.value = form.id;
const date = new Date(form.lastModified).toLocaleString('nl-NL');
option.textContent = form.label + ' (' + date + ')';
if (form.id === currentFormId) {
option.selected = true;
}
optgroup.appendChild(option);
});
selector.appendChild(optgroup);
}
}
// Load a specific form by ID
function loadFormById(formId) {
try {
const saved = localStorage.getItem(getStorageKey(formId));
if (saved) {
clearFormData();
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
currentFormId = formId;
updateFormSelector();
showToast('Formulier geladen: ' + formId, 'success');
}
} catch (e) {
console.warn('Could not load form:', e);
showToast('Kon formulier niet laden', 'error');
}
}
// Clear form data (without removing from storage)
function clearFormData() {
document.querySelectorAll('input[type="text"], input[type="number"], input[type="date"], select, textarea').forEach(field => {
field.value = '';
field.classList.remove('invalid');
});
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
document.querySelectorAll('.photo-preview').forEach(img => {
img.src = '';
img.style.display = 'none';
img.parentElement.classList.remove('has-photo');
});
history.replaceState(null, '', window.location.pathname);
}
// Load saved data from localStorage or URL
function loadSavedData() {
// Try URL hash first
@ -717,24 +931,20 @@ input.invalid, select.invalid, textarea.invalid {
params.forEach((value, key) => {
setFieldValue(key, value);
});
currentFormId = getFormUniqueId();
return;
} catch (e) {
console.warn('Could not parse URL hash:', e);
}
}
// Try localStorage
// Try to load most recent form from localStorage
if (CONFIG.autosave.use_localstorage) {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
}
} catch (e) {
console.warn('Could not load from localStorage:', e);
const forms = getSavedForms();
if (forms.length > 0) {
// Load most recent
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
loadFormById(forms[0].id);
}
}
}
@ -803,11 +1013,33 @@ input.invalid, select.invalid, textarea.invalid {
// Save data
function saveData() {
const data = getFormData();
const formId = getFormUniqueId();
// Only save if we have a valid form ID
if (!formId) {
updateSaveIndicator('waiting');
return;
}
// Save to localStorage
// Save to localStorage with form-specific key
if (CONFIG.autosave.use_localstorage) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
localStorage.setItem(getStorageKey(formId), JSON.stringify(data));
// Build label from unique ID fields
const labelParts = [];
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value) {
labelParts.push(field.value);
}
});
}
const label = labelParts.join(' - ') || formId;
saveFormToIndex(formId, label);
currentFormId = formId;
} catch (e) {
console.warn('Could not save to localStorage:', e);
}
@ -864,7 +1096,8 @@ input.invalid, select.invalid, textarea.invalid {
const statusText = {
'loaded': 'Gegevens geladen',
'saving': 'Opslaan...',
'saved': 'Opgeslagen ✓'
'saved': 'Opgeslagen ✓',
'waiting': 'Vul ID-velden in om op te slaan'
};
indicator.textContent = statusText[status] || status;
@ -1163,12 +1396,32 @@ input.invalid, select.invalid, textarea.invalid {
img.parentElement.classList.remove('has-photo');
});
localStorage.removeItem(STORAGE_KEY);
history.replaceState(null, '', window.location.pathname);
currentFormId = null;
updateFormSelector();
showToast('Formulier gewist', 'success');
};
// Delete saved form
window.deleteForm = function() {
if (!currentFormId) {
showToast('Geen formulier geselecteerd om te verwijderen', 'error');
return;
}
if (!confirm('Weet u zeker dat u dit opgeslagen formulier wilt verwijderen?\n\nFormulier: ' + currentFormId)) {
return;
}
removeFormFromIndex(currentFormId);
clearFormData();
currentFormId = null;
updateFormSelector();
showToast('Formulier verwijderd', 'success');
};
// Show toast notification
function showToast(message, type) {
const toast = document.getElementById('toast');

@ -1,6 +1,27 @@
# EasySmartInventory - Progress Log
## Session 1 - 2026-01-12
## Session 2 - 2026-01-12 (v1.0.1)
### New Feature: Form History
- [x] Added `unique_id_fields` to YAML schema
- [x] Updated yaml_parser.py for new config
- [x] JavaScript multi-form storage with index
- [x] Form selector dropdown in UI
- [x] "Nieuw formulier" button
- [x] "Verwijder" button for saved forms
- [x] Auto-detection of existing forms by unique ID
- [x] Version bump to 1.0.1
### How it works:
1. Configure `unique_id_fields` in YAML (e.g., serienummer, asset_id)
2. When user fills in these fields, form is saved with unique ID
3. Dropdown shows all saved forms with last modified date
4. User can switch between forms or start new one
5. Forms persist in localStorage per device
---
## Session 1 - 2026-01-12 (v1.0.0)
### Completed
- [x] Requirements analysis van EasySmartInventorie.txt
@ -15,26 +36,9 @@
- [x] JavaScript auto-save, validation, CSV export, mailto
- [x] Alle field types geïmplementeerd
- [x] 3 voorbeeld HTML bestanden gegenereerd
- [x] Base64 foto's in email body
### Generated Files
- `examples/inventory_modern.html` (35,456 bytes)
- `examples/inventory_corporate.html` (33,894 bytes)
- `examples/inventory_minimal.html` (34,481 bytes)
### Features Implemented
- ✅ YAML configuratie parsing
- ✅ 8 field types: text, number, date, textarea, dropdown, multiselect, boolean, photo
- ✅ Validatie (required, min_length, min/max)
- ✅ Auto-save naar localStorage
- ✅ URL hash voor state sharing
- ✅ CSV export met base64 foto's
- ✅ Mailto met configureerbare prefix
- ✅ 3 responsive themes
- ✅ Company logo support
- ✅ Versienummer tracking
### Notes
- Mailto kan geen echte bijlagen - foto's worden apart vermeld in email body
- LocalStorage + URL hash voor state management
- Alle CSS/JS inline voor standalone HTML
- UTF-8 BOM toegevoegd aan CSV voor Excel compatibiliteit
- `examples/inventory_modern.html`
- `examples/inventory_corporate.html`
- `examples/inventory_minimal.html`

@ -112,21 +112,71 @@ def generate_html(config: InventoryConfig) -> str:
"include_timestamp": config.export.mailto.include_timestamp,
},
},
"unique_id_fields": config.unique_id_fields,
}
# CSS genereren
css = get_theme_css(config.style.theme, config.style)
# Extra CSS voor photo container
# Extra CSS voor photo container en form selector
css += """
.photo-container.has-photo .photo-placeholder { display: none; }
.photo-container.has-photo .photo-preview { display: block !important; }
.photo-container.has-photo .photo-buttons { display: flex !important; }
.form-selector-container {
padding: 15px 30px;
background: linear-gradient(to right, #f8f9fa, #e9ecef);
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.form-selector-container label {
font-weight: 600;
margin: 0;
white-space: nowrap;
}
.form-selector-container select {
flex: 1;
min-width: 200px;
max-width: 400px;
}
.form-selector-container .btn {
padding: 8px 16px;
font-size: 0.9em;
}
@media (max-width: 768px) {
.form-selector-container {
flex-direction: column;
align-items: stretch;
}
.form-selector-container select {
max-width: 100%;
}
}
"""
# JavaScript met config
js = JAVASCRIPT.replace("{CONFIG_JSON}", json.dumps(js_config, ensure_ascii=False))
# Form selector HTML (alleen als unique_id_fields geconfigureerd zijn)
form_selector_html = ""
if config.unique_id_fields:
form_selector_html = '''<div class="form-selector-container">
<label for="form-selector">📋 Opgeslagen formulieren:</label>
<select id="form-selector">
<option value="">-- Selecteer --</option>
</select>
<button type="button" class="btn btn-danger" onclick="deleteForm()">🗑 Verwijder</button>
</div>
'''
# Secties genereren
sections_html = ""
for section in config.sections:
@ -154,7 +204,7 @@ def generate_html(config: InventoryConfig) -> str:
actions_html += ' <button type="button" class="btn btn-primary" onclick="exportCSV()">📥 Exporteer CSV</button>\n'
if config.export.mailto.enabled:
actions_html += ' <button type="button" class="btn btn-success" onclick="sendEmail(this)">📧 Verstuur per Email</button>\n'
actions_html += ' <button type="button" class="btn btn-danger" onclick="clearForm()">🗑️ Formulier Wissen</button>\n'
actions_html += ' <button type="button" class="btn btn-secondary" onclick="clearForm()">🔄 Nieuw Formulier</button>\n'
actions_html += '</div>\n'
# Complete HTML
@ -177,6 +227,7 @@ def generate_html(config: InventoryConfig) -> str:
<div class="version">Versie {config.version}</div>
</header>
{form_selector_html}
<form id="inventory-form" onsubmit="return false;">
{sections_html}
{actions_html}

@ -943,12 +943,14 @@ JAVASCRIPT = """
'use strict';
const CONFIG = {CONFIG_JSON};
const STORAGE_KEY = 'inventory_' + CONFIG.name + '_' + CONFIG.version;
const FORMS_INDEX_KEY = 'inventory_' + CONFIG.name + '_forms_index';
let currentFormId = null;
let saveTimeout = null;
let hasChanges = false;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
setupFormSelector();
loadSavedData();
setupAutoSave();
setupValidation();
@ -956,6 +958,173 @@ JAVASCRIPT = """
updateSaveIndicator('loaded');
});
// Get unique form ID based on configured fields
function getFormUniqueId() {
if (!CONFIG.unique_id_fields || CONFIG.unique_id_fields.length === 0) {
return 'default';
}
const parts = [];
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value && field.value.trim()) {
parts.push(field.value.trim());
}
});
return parts.length > 0 ? parts.join('_') : null;
}
// Get storage key for a specific form
function getStorageKey(formId) {
return 'inventory_' + CONFIG.name + '_' + CONFIG.version + '_form_' + formId;
}
// Get all saved forms from index
function getSavedForms() {
try {
const index = localStorage.getItem(FORMS_INDEX_KEY);
return index ? JSON.parse(index) : [];
} catch (e) {
return [];
}
}
// Save form to index
function saveFormToIndex(formId, label) {
const forms = getSavedForms();
const existing = forms.findIndex(f => f.id === formId);
const formInfo = {
id: formId,
label: label || formId,
lastModified: new Date().toISOString()
};
if (existing >= 0) {
forms[existing] = formInfo;
} else {
forms.push(formInfo);
}
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
updateFormSelector();
}
// Remove form from index
function removeFormFromIndex(formId) {
const forms = getSavedForms().filter(f => f.id !== formId);
localStorage.setItem(FORMS_INDEX_KEY, JSON.stringify(forms));
localStorage.removeItem(getStorageKey(formId));
updateFormSelector();
}
// Setup form selector dropdown
function setupFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
updateFormSelector();
selector.addEventListener('change', function() {
const selectedId = this.value;
if (selectedId === '__new__') {
clearFormData();
currentFormId = null;
showToast('Nieuw formulier gestart', 'success');
} else if (selectedId) {
loadFormById(selectedId);
}
});
// Watch unique ID fields for changes
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field) {
field.addEventListener('blur', function() {
const newId = getFormUniqueId();
if (newId && newId !== currentFormId) {
// Check if this form already exists
const existing = getSavedForms().find(f => f.id === newId);
if (existing) {
if (confirm('Er bestaat al een formulier met deze ID. Wilt u dit formulier laden?')) {
loadFormById(newId);
}
}
}
});
}
});
}
}
// Update form selector options
function updateFormSelector() {
const selector = document.getElementById('form-selector');
if (!selector) return;
const forms = getSavedForms();
const currentValue = selector.value;
// Clear and rebuild
selector.innerHTML = '<option value="">-- Selecteer opgeslagen formulier --</option>';
selector.innerHTML += '<option value="__new__"> Nieuw formulier</option>';
if (forms.length > 0) {
const optgroup = document.createElement('optgroup');
optgroup.label = 'Opgeslagen formulieren (' + forms.length + ')';
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
forms.forEach(form => {
const option = document.createElement('option');
option.value = form.id;
const date = new Date(form.lastModified).toLocaleString('nl-NL');
option.textContent = form.label + ' (' + date + ')';
if (form.id === currentFormId) {
option.selected = true;
}
optgroup.appendChild(option);
});
selector.appendChild(optgroup);
}
}
// Load a specific form by ID
function loadFormById(formId) {
try {
const saved = localStorage.getItem(getStorageKey(formId));
if (saved) {
clearFormData();
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
currentFormId = formId;
updateFormSelector();
showToast('Formulier geladen: ' + formId, 'success');
}
} catch (e) {
console.warn('Could not load form:', e);
showToast('Kon formulier niet laden', 'error');
}
}
// Clear form data (without removing from storage)
function clearFormData() {
document.querySelectorAll('input[type="text"], input[type="number"], input[type="date"], select, textarea').forEach(field => {
field.value = '';
field.classList.remove('invalid');
});
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
document.querySelectorAll('.photo-preview').forEach(img => {
img.src = '';
img.style.display = 'none';
img.parentElement.classList.remove('has-photo');
});
history.replaceState(null, '', window.location.pathname);
}
// Load saved data from localStorage or URL
function loadSavedData() {
// Try URL hash first
@ -966,24 +1135,20 @@ JAVASCRIPT = """
params.forEach((value, key) => {
setFieldValue(key, value);
});
currentFormId = getFormUniqueId();
return;
} catch (e) {
console.warn('Could not parse URL hash:', e);
}
}
// Try localStorage
// Try to load most recent form from localStorage
if (CONFIG.autosave.use_localstorage) {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
const data = JSON.parse(saved);
Object.entries(data).forEach(([key, value]) => {
setFieldValue(key, value);
});
}
} catch (e) {
console.warn('Could not load from localStorage:', e);
const forms = getSavedForms();
if (forms.length > 0) {
// Load most recent
forms.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
loadFormById(forms[0].id);
}
}
}
@ -1052,11 +1217,33 @@ JAVASCRIPT = """
// Save data
function saveData() {
const data = getFormData();
const formId = getFormUniqueId();
// Only save if we have a valid form ID
if (!formId) {
updateSaveIndicator('waiting');
return;
}
// Save to localStorage
// Save to localStorage with form-specific key
if (CONFIG.autosave.use_localstorage) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
localStorage.setItem(getStorageKey(formId), JSON.stringify(data));
// Build label from unique ID fields
const labelParts = [];
if (CONFIG.unique_id_fields) {
CONFIG.unique_id_fields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (field && field.value) {
labelParts.push(field.value);
}
});
}
const label = labelParts.join(' - ') || formId;
saveFormToIndex(formId, label);
currentFormId = formId;
} catch (e) {
console.warn('Could not save to localStorage:', e);
}
@ -1113,7 +1300,8 @@ JAVASCRIPT = """
const statusText = {
'loaded': 'Gegevens geladen',
'saving': 'Opslaan...',
'saved': 'Opgeslagen ✓'
'saved': 'Opgeslagen ✓',
'waiting': 'Vul ID-velden in om op te slaan'
};
indicator.textContent = statusText[status] || status;
@ -1412,12 +1600,32 @@ JAVASCRIPT = """
img.parentElement.classList.remove('has-photo');
});
localStorage.removeItem(STORAGE_KEY);
history.replaceState(null, '', window.location.pathname);
currentFormId = null;
updateFormSelector();
showToast('Formulier gewist', 'success');
};
// Delete saved form
window.deleteForm = function() {
if (!currentFormId) {
showToast('Geen formulier geselecteerd om te verwijderen', 'error');
return;
}
if (!confirm('Weet u zeker dat u dit opgeslagen formulier wilt verwijderen?\\n\\nFormulier: ' + currentFormId)) {
return;
}
removeFormFromIndex(currentFormId);
clearFormData();
currentFormId = null;
updateFormSelector();
showToast('Formulier verwijderd', 'success');
};
// Show toast notification
function showToast(message, type) {
const toast = document.getElementById('toast');

@ -85,11 +85,12 @@ class AutosaveConfig:
class InventoryConfig:
"""Hoofdconfiguratie voor inventarisatie"""
name: str
version: str = "1.0.0"
version: str = "1.0.1"
style: StyleConfig = field(default_factory=StyleConfig)
export: ExportConfig = field(default_factory=ExportConfig)
autosave: AutosaveConfig = field(default_factory=AutosaveConfig)
sections: list[SectionConfig] = field(default_factory=list)
unique_id_fields: list[str] = field(default_factory=list)
def parse_field(field_data: dict) -> FieldConfig:
@ -182,11 +183,12 @@ def parse_yaml(yaml_path: str) -> InventoryConfig:
return InventoryConfig(
name=data.get("name", "Inventarisatie"),
version=data.get("version", "1.0.0"),
version=data.get("version", "1.0.1"),
style=parse_style(data.get("style", {})),
export=parse_export(data.get("export", {})),
autosave=parse_autosave(data.get("autosave", {})),
sections=sections,
unique_id_fields=data.get("unique_id_fields", []),
)

Loading…
Cancel
Save

Powered by TurnKey Linux.