Files
machineGroupControl/mgc.html
znetsixe 6833e9f3a8 feat(mgc): consume shared icon-picker visuals + modernize editor menu
* compact-fields.js (new): trimmed to MGC-only output-format pickers
  (processOutputFormat / dbaseOutputFormat). The logger toggle/level
  and physical-position visuals now come from generalFunctions'
  shared iconHelpers, auto-injected via /machineGroupControl/menu.js.
* mode-cards.js: strategy cards re-styled — Most-efficient (BEP bell
  with dot on the curve peak), Priority (clean staircase), Maintenance
  (Font Awesome fa-wrench). Rendezvous toggle flips Active / Inactive
  label dynamically.
* mgc.html: dropped the duplicated .mgc-icon-* CSS rules (now live in
  the shared iconHelpers stylesheet). Strategy + rendezvous CSS stays
  local (MGC-specific). Output picker holders switched to the shared
  .evolv-icon-picker class.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 11:10:54 +02:00

198 lines
8.2 KiB
HTML

<!--
| S88-niveau | Primair (blokkleur) | Tekstkleur |
| ---------------------- | ------------------- | ---------- |
| **Area** | `#0f52a5` | wit |
| **Process Cell** | `#0c99d9` | wit |
| **Unit** | `#50a8d9` | zwart |
| **Equipment (Module)** | `#86bbdd` | zwart |
| **Control Module** | `#a9daee` | zwart |
-->
<script src="/machineGroupControl/menu.js"></script> <!-- Load the menu script for dynamic dropdowns -->
<script src="/machineGroupControl/configData.js"></script> <!-- Load the config script for node information -->
<!-- Editor JS modules — see nodes/machineGroupControl/src/editor/. Loaded in
dependency order: index.js (namespace + helpers) → modules → oneditprepare. -->
<script src="/machineGroupControl/editor/index.js"></script>
<script src="/machineGroupControl/editor/mode-cards.js"></script>
<script src="/machineGroupControl/editor/compact-fields.js"></script>
<script src="/machineGroupControl/editor/oneditprepare.js"></script>
<style>
/* MGC-specific UI: strategy mode cards + rendezvous toggle.
Generic .evolv-icon-picker / .evolv-icon-option styles for the
output-format pickers come from generalFunctions' iconHelpers (auto-
injected by /menu.js). */
.mgc-mode-cards,
.mgc-toggle-row { display:flex; gap:6px; flex-wrap:wrap; margin:6px 0 4px 0; }
.mgc-mode-card,
.mgc-toggle-card {
width:94px; height:86px; box-sizing:border-box;
border:2px solid #d0d0d0; border-radius:4px; background:#fafafa;
padding:4px; cursor:pointer; user-select:none;
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
transition:border-color 80ms ease-out, background 80ms ease-out;
}
.mgc-mode-card:hover,
.mgc-toggle-card:hover { border-color:#86bbdd; background:#f5fafd; }
.mgc-mode-card:focus,
.mgc-toggle-card:focus { outline:2px solid #1F4E79; outline-offset:2px; }
.mgc-mode-card-on,
.mgc-toggle-card-on { border-color:#50a8d9; background:#eaf4fb; }
.mgc-mode-card-svg,
.mgc-toggle-card-svg { width:100%; height:54px; display:flex; align-items:center; justify-content:center; }
.mgc-mode-card-svg svg,
.mgc-toggle-card-svg svg { width:100%; height:100%; display:block; }
.mgc-mode-card-label,
.mgc-toggle-card-label { font-size:10px; line-height:1; font-weight:600; color:#333; white-space:nowrap; letter-spacing:0; }
.mgc-toggle-card:not(.mgc-toggle-card-on) .mgc-toggle-card-svg { opacity:0.45; filter:grayscale(1); }
.mgc-toggle-card:not(.mgc-toggle-card-on) .mgc-toggle-card-label { color:#888; }
.mgc-hidden-checkbox { position:absolute; opacity:0; width:1px; height:1px; pointer-events:none; }
.mgc-section-divider { border:0; border-top:1px solid #d6d6d6; margin:12px 0; }
.mgc-output-row > label { white-space:nowrap; width:130px; }
</style>
<script>
RED.nodes.registerType('machineGroupControl',{
category: "EVOLV",
color: "#50a8d9",
defaults: {
// Define default properties
name: { value: "" },
processOutputFormat: { value: "process" },
dbaseOutputFormat: { value: "influxdb" },
// Control strategy
mode: { value: "optimalControl" }, // optimalControl | priorityControl | maintenance
// Same-time landing (rendezvous planner). When ON the planner
// delays each pump's move so all pumps reach their setpoint at
// the same wall-clock instant t* = max(eta_i). When OFF each
// pump moves at its own pace and lands at its own eta.
useRendezvous: { value: true },
//define asset properties
uuid: { value: "" },
supplier: { value: "" },
category: { value: "" },
assetType: { value: "" },
model: { value: "" },
unit: { value: "" },
// Logger properties
enableLog: { value: false },
logLevel: { value: "error" },
//physicalAspect
positionVsParent: { value: "" },
positionIcon: { value: "" },
hasDistance: { value: false },
distance: { value: 0 },
distanceUnit: { value: "m" },
distanceDescription: { value: "" }
},
inputs:1,
outputs:3,
inputLabels: ["Input"],
outputLabels: ["process", "dbase", "parent"],
icon: "font-awesome/fa-cogs",
label: function () {
return (this.positionIcon || "") + " machineGroup";
},
oneditprepare: function() {
const self = this;
// Initialize the menu data for the node, then the visual modules.
// Both attach to window.EVOLV.nodes.machineGroupControl.* — the
// menu endpoint populates loggerMenu/positionMenu/initEditor; the
// editor scripts populate editor.modeCards/rendezvousToggle/compactFields.
const waitForMenuData = () => {
if (window.EVOLV?.nodes?.machineGroupControl?.initEditor) {
window.EVOLV.nodes.machineGroupControl.initEditor(self);
if (window.EVOLV.nodes.machineGroupControl.editor?.initVisuals) {
window.EVOLV.nodes.machineGroupControl.editor.initVisuals(self);
}
} else {
setTimeout(waitForMenuData, 50);
}
};
// Wait for the menu data to be ready before initializing the editor
waitForMenuData();
},
oneditsave: function(){
const node = this;
// Validate logger properties using the logger menu
if (window.EVOLV?.nodes?.machineGroupControl?.loggerMenu?.saveEditor) {
success = window.EVOLV.nodes.machineGroupControl.loggerMenu.saveEditor(node);
}
// save position field
if (window.EVOLV?.nodes?.machineGroupControl?.positionMenu?.saveEditor) {
window.EVOLV.nodes.machineGroupControl.positionMenu.saveEditor(this);
}
}
});
</script>
<script type="text/html" data-template-name="machineGroupControl">
<h3>Control strategy</h3>
<!-- Hidden input is the canonical Node-RED-readable field. The visible
picker is rendered by src/editor/mode-cards.js into the placeholder
below, and clicks on a card write back to this input. -->
<input type="hidden" id="node-input-mode" />
<div id="mgc-mode-cards" class="mgc-mode-cards"
role="radiogroup" aria-label="Control strategy mode">
<!-- mode-cards.js renders three card divs here -->
</div>
<hr class="mgc-section-divider" />
<h3>Rendezvous planner</h3>
<div class="form-row mgc-toggle-row">
<input type="checkbox" id="node-input-useRendezvous" class="mgc-hidden-checkbox" />
<div id="mgc-rendezvous-toggle" class="mgc-toggle-card"
role="switch" tabindex="0" aria-label="Same-time landing"
aria-checked="false" title="Same-time landing"></div>
</div>
<hr class="mgc-section-divider" />
<h3>Output Formats</h3>
<div class="form-row mgc-output-row">
<label for="node-input-processOutputFormat"><i class="fa fa-random"></i> Process Output</label>
<select id="node-input-processOutputFormat" class="evolv-native-hidden" style="width:60%;">
<option value="process">process</option>
<option value="json">json</option>
<option value="csv">csv</option>
</select>
<div id="mgc-process-output-picker" class="evolv-icon-picker"
role="radiogroup" aria-label="Process output format"></div>
</div>
<div class="form-row mgc-output-row">
<label for="node-input-dbaseOutputFormat"><i class="fa fa-database"></i> Database Output</label>
<select id="node-input-dbaseOutputFormat" class="evolv-native-hidden" style="width:60%;">
<option value="influxdb">influxdb</option>
<option value="json">json</option>
<option value="csv">csv</option>
</select>
<div id="mgc-dbase-output-picker" class="evolv-icon-picker"
role="radiogroup" aria-label="Database output format"></div>
</div>
<hr class="mgc-section-divider" />
<!-- Logger fields injected here -->
<div id="logger-fields-placeholder"></div>
<!-- Position fields injected here -->
<div id="position-fields-placeholder"></div>
</script>
<script type="text/html" data-help-name="machineGroupControl">
<p>A machineGroupControl node</p>
</script>