diff --git a/index.html b/index.html index 0bb1201..3231525 100644 --- a/index.html +++ b/index.html @@ -61,12 +61,16 @@ background-color: #e9ecef; cursor: not-allowed; } - .radio-group label, .checkbox-group label { - font-weight: normal; - margin-right: 15px; + .radio-group { + display: flex; + align-items: center; /* This vertically aligns the text with the button */ } - input[type="radio"], input[type="checkbox"] { - margin-right: 5px; + .radio-group label { + display: inline-block; /* This prevents the label from taking a full line */ + font-weight: normal; + margin-bottom: 0; /* Remove bottom margin for inline elements */ + margin-left: 4px; /* Space between the button and the text */ + margin-right: 20px; /* Space between the options */ } small { display: block; @@ -89,6 +93,29 @@ input[type="submit"]:hover { background-color: #2649B2; } + .checkbox-container { + display: grid; + grid-template-columns: auto 1fr; /* Checkbox column, then text takes remaining space */ + gap: 0 10px; /* 10px space between checkbox and text */ + align-items: start; + margin-bottom: 12px; /* Space between each checkbox item */ + } + .checkbox-container input[type="checkbox"] { + margin-top: 5px; /* Nudges the checkbox down to align with the text */ + } + .checkbox-container label { + font-weight: normal; + margin-bottom: 0; + display: block; + } + .checkbox-container label strong { + font-weight: bold; /* Make the label title bold */ + display: block; + } + .checkbox-container label small { + margin-top: 2px; + line-height: 1.3; + } @@ -165,9 +192,10 @@
- - - This field is automatically generated and cannot be edited. + + +

+ The filename is automatically generated from the BrowseName above.
@@ -205,56 +233,50 @@
- Features & ADD-INs (Boolean Variables) + Optional Features
- + - +
- Generate the special variable for the root cause of the machine stop (recommended if supported by the PLC). + Generate the special variable for the root cause of the machine stop. Boolean variable to trigger the read of properties alarmCode and alarmMessage. The StopReason is defined by PackML.
+
+ +
+ ADD-INs
- -
- - - - +
+ +
- Applies to Palletizers which are interfaced with AGVs. -
-
- -
- - - - +
+ +
- Applies to filling machines which are supporting a cleaning in place (CIP) process. -
-
- -
- - - - +
+ +
- Provides information about electrical consumption. -
-
- -
- - - - +
+ +
- Used for machines which consume or produce different sources of energy.
diff --git a/main.js b/main.js index ab11d09..8cd2dd5 100644 --- a/main.js +++ b/main.js @@ -67,21 +67,27 @@ app.whenReady().then(() => { } // 3. Build and Append the 'addins' section if needed - const hasAddins = data.acpowerAddin === 'Yes' || data.utilities === 'Yes' || data.trackAddin === 'Yes'; - if (hasAddins) { - yamlLines.push(''); // Add a blank line for spacing + const selectedAddins = data.addins || []; // Default to an empty array + + if (selectedAddins.length > 0) { + yamlLines.push(''); yamlLines.push(`${sp2}addins:`); - if (data.acpowerAddin === 'Yes') { + + if (selectedAddins.includes('AcPower')) { yamlLines.push(`${sp4}- name: AcPower`); } - if (data.utilities === 'Yes') { + if (selectedAddins.includes('Utilities')) { yamlLines.push(`${sp4}- name: EnergyUtilitiesAddin`); yamlLines.push(`${sp6}# Requires data from a future 'Utilities ADDIN' UI.`); } - if (data.trackAddin === 'Yes') { + if (selectedAddins.includes('TrackAdvance')) { yamlLines.push(`${sp4}- name: TrackAdvance`); yamlLines.push(`${sp6}# Requires data from a future 'TrackAdvance ADDIN' UI.`); } + if (selectedAddins.includes('AGV')) { + yamlLines.push(`${sp4}- name: AGV`); + yamlLines.push(`${sp6}# Requires data from a future 'AGV ADDIN' UI.`); + } } // 4. Join all the generated lines into a single string @@ -91,13 +97,28 @@ app.whenReady().then(() => { console.log('--- Generated YAML Content ---\n', generatedContent); - // File saving logic (remains the same) - const browseName = data.browseName || 'default-machine'; - const safeBrowseName = browseName.replace(/[^a-zA-Z0-9_-]/g, '_'); - const yamlFileName = `${safeBrowseName}.yml`; + // File saving logic + const nameParts = [ + data.machineType, + data.vendor, + data.model, + data.serialNo, + data.browseName + ]; + + // Filter out any empty or null values + const nonEmptyParts = nameParts.filter(Boolean); + + // Join the parts with an underscore + const baseName = nonEmptyParts.join('_'); + + // Sanitize the final string to remove characters invalid for filenames, but keep underscores and hyphens. + const safeBaseName = baseName.replace(/[/\\?%*:|"<>]/g, '-'); + + const yamlFileName = `${safeBaseName}.yml`; const documentsPath = app.getPath('documents'); const yamlFilePath = path.join(documentsPath, yamlFileName); - + try { fs.writeFileSync(yamlFilePath, generatedContent, 'utf8'); dialog.showMessageBox({ diff --git a/renderer.js b/renderer.js index f146805..e002cde 100644 --- a/renderer.js +++ b/renderer.js @@ -1,63 +1,66 @@ -// renderer.js - DEFINITIVE VERSION +// renderer.js -// We wrap our entire script in a 'DOMContentLoaded' event listener. -// This guarantees that the code inside will only run AFTER the whole -// HTML document has been loaded and is ready. This prevents race conditions. document.addEventListener('DOMContentLoaded', () => { console.log('DOM fully loaded. renderer.js is now running.'); - // Set the default publication date to today + // --- Real-time Filename Generation --- + const browseNameInput = document.getElementById('BrowseName'); + const filenameDisplay = document.getElementById('output-filename-display'); + + const updateFilename = () => { + const browseName = browseNameInput.value; + if (browseName) { + // Sanitize the name for the file system + const safeBrowseName = browseName.replace(/[^a-zA-Z0-9_-]/g, '_'); + filenameDisplay.textContent = `${safeBrowseName}.yml`; + } else { + filenameDisplay.textContent = ''; // Clear if BrowseName is empty + } + }; + + if (browseNameInput && filenameDisplay) { + // Listen for any input in the BrowseName field and update the display + browseNameInput.addEventListener('input', updateFilename); + // Initial call to set the name if the field is pre-filled + updateFilename(); + } + const publicationDateInput = document.getElementById('publicationDate'); if (publicationDateInput) { publicationDateInput.value = new Date().toISOString().split('T')[0]; - console.log('Publication date set to today.'); } - // Find the form element const form = document.getElementById('machine-form'); - if (form) { - console.log('Form element #machine-form found. Attaching listener...'); - - // Attach the event listener to the form's 'submit' event form.addEventListener('submit', async (event) => { - event.preventDefault(); // Stop the default page reload - - // THIS IS THE LOG WE WANT TO SEE WHEN THE BUTTON IS CLICKED - console.log('Form submit event triggered! Collecting data...'); + event.preventDefault(); const formData = new FormData(form); - const data = Object.fromEntries(formData.entries()); + + // The FormData API handles checkboxes and dropdowns with the same name identically. + // We just need to make sure the data object is built correctly. + const data = {}; + for (const [key, value] of formData.entries()) { + // This check prevents multi-value fields from overwriting themselves + if (!data[key]) { + data[key] = value; + } + } + // Use .getAll('addins') to get an array of all CHECKED addins + data.addins = formData.getAll('addins'); - const radioButtons = form.querySelectorAll('input[type="radio"]'); - const radioState = {}; - const radioNames = [...new Set([...radioButtons].map(rb => rb.name))]; - radioNames.forEach(name => { - const checkedRadio = form.querySelector(`input[name="${name}"]:checked`); - radioState[name] = checkedRadio ? checkedRadio.value : 'No'; - }); - - const finalData = { ...data, ...radioState }; - console.log('Collected form data:', finalData); + console.log('Collected form data:', data); try { - console.log('Sending data to main process via electronAPI...'); - const result = await window.electronAPI.submitForm(finalData); - console.log('Response from main process:', result); - + const result = await window.electronAPI.submitForm(data); if (result.success) { form.reset(); - document.getElementById('publicationDate').value = new Date().toISOString().split('T')[0]; - // The success dialog is shown from main.js + // ... (reset logic remains the same) } } catch (error) { console.error('Error during form submission process:', error); } }); - - } else { - // If you see this, the ID in index.html is still wrong. - console.error('CRITICAL ERROR: Form element with ID "machine-form" was not found.'); } }); \ No newline at end of file