Final Version of the machine description, fully working
This commit is contained in:
parent
a1dcf26b85
commit
1f42ce3ad2
116
index.html
116
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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -165,9 +192,10 @@
|
||||
<input type="text" id="version" name="version" placeholder="Ex: 1.0.0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="outputFile">Output File</label>
|
||||
<input type="text" id="outputFile" name="outputFile" value="Automatically generated (YAML)" readonly>
|
||||
<small>This field is automatically generated and cannot be edited.</small>
|
||||
<label>Output Filename</label>
|
||||
<!-- This is where the generated filename will be displayed -->
|
||||
<p id="output-filename-display" style="font-family: monospace; background-color: #e9ecef; padding: 10px; border-radius: 5px;"></p>
|
||||
<small>The filename is automatically generated from the BrowseName above.</small>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@ -205,56 +233,50 @@
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Features & ADD-INs (Boolean Variables)</legend>
|
||||
<legend>Optional Features</legend>
|
||||
<div class="form-group">
|
||||
<label>StopReason Generation</label>
|
||||
<div class="radio-group">
|
||||
<input type="radio" id="stopReasonYes" name="stopReason" value="Yes">
|
||||
<input type="radio" id="stopReasonYes" name="stopReason" value="Yes" checked>
|
||||
<label for="stopReasonYes">Yes</label>
|
||||
<input type="radio" id="stopReasonNo" name="stopReason" value="No" checked>
|
||||
<input type="radio" id="stopReasonNo" name="stopReason" value="No">
|
||||
<label for="stopReasonNo">No</label>
|
||||
</div>
|
||||
<small>Generate the special variable for the root cause of the machine stop (recommended if supported by the PLC).</small>
|
||||
<small>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.</small>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>ADD-INs</legend>
|
||||
<div class="form-group">
|
||||
<label>AGV ADDIN</label>
|
||||
<div class="radio-group">
|
||||
<input type="radio" id="agvYes" name="agvAddin" value="Yes">
|
||||
<label for="agvYes">Yes</label>
|
||||
<input type="radio" id="agvNo" name="agvAddin" value="No" checked>
|
||||
<label for="agvNo">No</label>
|
||||
</div>
|
||||
<small>Applies to Palletizers which are interfaced with AGVs.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>TrackAdvance ADDIN</label>
|
||||
<div class="radio-group">
|
||||
<input type="radio" id="trackYes" name="trackAddin" value="Yes">
|
||||
<label for="trackYes">Yes</label>
|
||||
<input type="radio" id="trackNo" name="trackAddin" value="No" checked>
|
||||
<label for="trackNo">No</label>
|
||||
</div>
|
||||
<small>Applies to filling machines which are supporting a cleaning in place (CIP) process.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ACPower ADDIN</label>
|
||||
<div class="radio-group">
|
||||
<input type="radio" id="acYes" name="acpowerAddin" value="Yes">
|
||||
<label for="acYes">Yes</label>
|
||||
<input type="radio" id="acNo" name="acpowerAddin" value="No" checked>
|
||||
<label for="acNo">No</label>
|
||||
</div>
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" id="addins-acpower" name="addins" value="AcPower">
|
||||
<label for="addins-acpower">
|
||||
<strong>ACPower ADDIN</strong>
|
||||
<small>Provides information about electrical consumption.</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Utilities ADDIN</label>
|
||||
<div class="radio-group">
|
||||
<input type="radio" id="utilYes" name="utilities" value="Yes">
|
||||
<label for="utilYes">Yes</label>
|
||||
<input type="radio" id="utilNo" name="utilities" value="No" checked>
|
||||
<label for="utilNo">No</label>
|
||||
</div>
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" id="addins-utilities" name="addins" value="Utilities">
|
||||
<label for="addins-utilities">
|
||||
<strong>Utilities ADDIN</strong>
|
||||
<small>Used for machines which consume or produce different sources of energy.</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" id="addins-trackadvance" name="addins" value="TrackAdvance">
|
||||
<label for="addins-trackadvance">
|
||||
<strong>TrackAdvance ADDIN</strong>
|
||||
<small>Applies to filling machines supporting a cleaning in place (CIP) process.</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" id="addins-agv" name="addins" value="AGV">
|
||||
<label for="addins-agv">
|
||||
<strong>AGV ADDIN</strong>
|
||||
<small>Applies to Palletizers which are interfaced with AGVs.</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
41
main.js
41
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,10 +97,25 @@ 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);
|
||||
|
||||
|
||||
73
renderer.js
73
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());
|
||||
|
||||
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';
|
||||
});
|
||||
// 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 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.');
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user