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>
This commit is contained in:
znetsixe
2026-05-18 11:10:54 +02:00
parent 472402c62d
commit 6833e9f3a8
4 changed files with 218 additions and 115 deletions

View File

@@ -15,24 +15,41 @@
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>
/* Mode-card picker. Three cards stack horizontally; on a narrow editor pane
they wrap. Selected card gets a thick #50a8d9 (Unit-colour) border. */
.mgc-mode-cards { display:flex; gap:8px; flex-wrap:wrap; margin:6px 0 4px 0; }
.mgc-mode-card {
flex:1 1 0; min-width:140px; box-sizing:border-box;
/* 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:6px 8px 8px 8px; cursor:pointer; user-select:none;
display:flex; flex-direction:column; gap:4px;
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 { border-color:#86bbdd; background:#f5fafd; }
.mgc-mode-card-on { border-color:#50a8d9; background:#eaf4fb; }
.mgc-mode-card-svg svg { width:100%; height:auto; max-height:90px; display:block; }
.mgc-mode-card-label { font-weight:600; font-size:12px; color:#333; }
.mgc-mode-card-caption { font-size:10px; color:#666; line-height:1.3; }
.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>
@@ -89,7 +106,7 @@
// 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/demandContract.
// editor scripts populate editor.modeCards/rendezvousToggle/compactFields.
const waitForMenuData = () => {
if (window.EVOLV?.nodes?.machineGroupControl?.initEditor) {
window.EVOLV.nodes.machineGroupControl.initEditor(self);
@@ -133,48 +150,39 @@
role="radiogroup" aria-label="Control strategy mode">
<!-- mode-cards.js renders three card divs here -->
</div>
<p style="margin-top:8px;color:#666;font-size:11px;">
Demand is self-describing per <code>set.demand</code> message: a bare number is
treated as % of group capacity; <code>{value, unit}</code> with a flow unit
(<code>m3/h</code>, <code>l/s</code>, <code>m3/s</code>, &hellip;) is dispatched
in absolute terms. Negative value stops all pumps.
</p>
<hr class="mgc-section-divider" />
<h3>Rendezvous planner</h3>
<div class="form-row" style="display:flex;align-items:center;gap:8px;">
<input type="checkbox" id="node-input-useRendezvous"
style="width:auto;margin:0;vertical-align:middle;" />
<label for="node-input-useRendezvous" style="width:auto;margin:0;cursor:pointer;">
Same-time landing
</label>
<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>
<p style="margin-top:4px;color:#666;font-size:11px;">
When enabled (default), every dispatch is routed through the rendezvous
planner regardless of control strategy: per-pump moves are delayed so all
pumps reach their setpoint at the same wall-clock instant
<code>t* = max(eta<sub>i</sub>)</code>. When disabled, every
<code>flowmovement</code> fires immediately and each pump ramps at its
own configured reaction speed (legacy behaviour).
</p>
<hr class="mgc-section-divider" />
<h3>Output Formats</h3>
<div class="form-row">
<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" style="width:60%;">
<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">
<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" style="width:60%;">
<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>