From ab481357d21c5ab9a3cf29359d242bc94f1d1c4d Mon Sep 17 00:00:00 2001 From: znetsixe Date: Mon, 18 May 2026 21:30:54 +0200 Subject: [PATCH] feat(menu): globalize output-format picker + tighter asset wizard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iconHelpers.js: * Add SVG.outputProcess/outputJson/outputCsv/outputInflux icons. * Add renderOutputFormatPicker(select, holder) shared helper. * Add idempotent upgradeOutputFormatSelects() that scans for node-input-processOutputFormat / dbaseOutputFormat selects and replaces them with icon pickers — no per-node HTML edits required. * Redesign SVG.upstream/atEquipment/downstream to a pump volute + sensor marker matching the rotatingMachine pump banner style. menu/index.js: * Auto-invoke upgradeOutputFormatSelects from MenuManager's initEditor wrapper so every node inherits the picker. asset.js: * Tighter chip styling: 1px border, 4px radius, 3x8 padding, no uppercase transform — single-line "Label: Value" instead of stacked card. * Narrower Asset Tag input (max 200px); wizard max-width 460px. * Restore curve preview to 220x110 (was over-compacted). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/menu/asset.js | 56 ++++++++------- src/menu/iconHelpers.js | 152 +++++++++++++++++++++++++++++++++++----- src/menu/index.js | 12 ++++ 3 files changed, 179 insertions(+), 41 deletions(-) diff --git a/src/menu/asset.js b/src/menu/asset.js index 1de399f..96c5fa4 100644 --- a/src/menu/asset.js +++ b/src/menu/asset.js @@ -104,49 +104,55 @@ class AssetMenu { const id = 'evolv-asset-wizard-css'; if (document.getElementById(id)) return; const css = [ + // Asset wizard — tightened layout (smaller radius/padding, no + // uppercase label transform, single-line chip text) so the strip + // reads as a compact form control instead of a row of pill cards. '.evolv-asset-hidden-natives { position:absolute !important; left:-9999px !important; height:0 !important; overflow:hidden; }', - '.evolv-asset-wizard { display:flex; flex-direction:column; gap:10px; margin:6px 0 4px 0; }', - '.evolv-asset-chips { display:flex; flex-wrap:wrap; gap:6px; align-items:center; }', + '.evolv-asset-wizard { display:flex; flex-direction:column; gap:8px; margin:6px 0 4px 0; max-width:460px; }', + '.evolv-asset-chips { display:flex; flex-wrap:wrap; gap:4px; align-items:center; }', '.evolv-asset-chip {', - ' display:flex; align-items:center; gap:8px;', - ' border:2px solid #d0d0d0; border-radius:18px; background:#fafafa;', - ' padding:6px 12px; cursor:pointer; user-select:none;', - ' font:inherit; color:#333;', + ' display:inline-flex; align-items:baseline; gap:6px;', + ' border:1px solid #d0d0d0; border-radius:4px; background:#fff;', + ' padding:3px 8px; cursor:pointer; user-select:none;', + ' font:inherit; color:#333; height:26px; box-sizing:border-box;', ' transition:border-color 80ms ease-out, background 80ms ease-out;', '}', '.evolv-asset-chip:hover { border-color:#86bbdd; background:#f5fafd; }', '.evolv-asset-chip[aria-selected="true"] { border-color:#1F4E79; background:#eaf4fb; }', '.evolv-asset-chip[disabled] { opacity:0.5; cursor:not-allowed; }', - '.evolv-asset-chip-icon { color:#1F4E79; font-size:14px; }', - '.evolv-asset-chip-text { display:flex; flex-direction:column; line-height:1.15; text-align:left; }', - '.evolv-asset-chip-label { font-size:10px; font-weight:600; color:#888; letter-spacing:0.5px; text-transform:uppercase; }', - '.evolv-asset-chip-value { font-size:13px; font-weight:600; color:#1F4E79; max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }', - '.evolv-asset-chip-value[data-empty="true"] { color:#aaa; font-weight:500; font-style:italic; }', - '.evolv-asset-chip-sep { color:#aaa; font-size:18px; line-height:1; user-select:none; }', - '.evolv-asset-combobox { display:flex; flex-direction:column; gap:4px; border:1px solid #d0d0d0; border-radius:4px; background:#fff; padding:8px; }', - '.evolv-asset-combobox-search { width:100%; box-sizing:border-box; padding:6px 8px; border:1px solid #ccc; border-radius:3px; font:inherit; }', + '.evolv-asset-chip-icon { color:#607484; font-size:11px; align-self:center; }', + '.evolv-asset-chip-text { display:inline-flex; align-items:baseline; gap:5px; line-height:1; }', + '.evolv-asset-chip-label { font-size:11px; font-weight:normal; color:#888; letter-spacing:0; text-transform:none; }', + '.evolv-asset-chip-label::after { content:":"; color:#bbb; margin-left:1px; }', + '.evolv-asset-chip-value { font-size:12px; font-weight:600; color:#1F4E79; max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }', + '.evolv-asset-chip-value[data-empty="true"] { color:#aaa; font-weight:400; font-style:italic; }', + '.evolv-asset-chip-sep { color:#bbb; font-size:13px; line-height:1; user-select:none; padding:0 2px; }', + '.evolv-asset-combobox { display:flex; flex-direction:column; gap:4px; border:1px solid #d0d0d0; border-radius:3px; background:#fff; padding:6px; }', + '.evolv-asset-combobox-search { width:100%; box-sizing:border-box; padding:5px 7px; border:1px solid #ccc; border-radius:3px; font:inherit; font-size:12px; }', '.evolv-asset-combobox-search:focus { outline:none; border-color:#1F4E79; box-shadow:0 0 0 2px rgba(31,78,121,0.15); }', - '.evolv-asset-combobox-list { max-height:220px; overflow-y:auto; }', + '.evolv-asset-combobox-list { max-height:200px; overflow-y:auto; }', '.evolv-asset-combobox-option {', - ' padding:6px 10px; cursor:pointer; border-radius:3px;', - ' font-size:13px; color:#333;', + ' padding:5px 8px; cursor:pointer; border-radius:2px;', + ' font-size:12px; color:#333;', '}', '.evolv-asset-combobox-option:hover,', '.evolv-asset-combobox-option.evolv-asset-combobox-option-active { background:#eaf4fb; color:#1F4E79; }', - '.evolv-asset-combobox-empty { padding:6px 10px; color:#888; font-size:12px; font-style:italic; }', - '.evolv-asset-summary { display:grid; grid-template-columns:1fr 200px; gap:12px; border:1px solid #e2e2e2; border-radius:4px; padding:10px 12px; background:#fafafa; align-items:center; }', - '.evolv-asset-specs { font-size:12px; color:#333; display:flex; flex-direction:column; gap:3px; }', + '.evolv-asset-combobox-empty { padding:5px 8px; color:#888; font-size:11px; font-style:italic; }', + '.evolv-asset-summary { display:grid; grid-template-columns:1fr 220px; gap:10px; border:1px solid #e2e2e2; border-radius:3px; padding:8px 10px; background:#fafafa; align-items:center; }', + '.evolv-asset-specs { font-size:11.5px; color:#333; display:flex; flex-direction:column; gap:2px; }', '.evolv-asset-spec-row { display:flex; gap:6px; }', - '.evolv-asset-spec-key { color:#888; min-width:80px; }', + '.evolv-asset-spec-key { color:#888; min-width:74px; }', '.evolv-asset-spec-val { color:#1F4E79; font-weight:600; }', - '.evolv-asset-curve { width:200px; height:90px; }', + '.evolv-asset-curve { width:220px; height:110px; }', '.evolv-asset-curve svg { width:100%; height:100%; display:block; }', '.evolv-asset-curve-empty { display:flex; align-items:center; justify-content:center; color:#aaa; font-size:11px; font-style:italic; text-align:center; }', - '.evolv-asset-tag-row { margin-top:4px; }', + '.evolv-asset-tag-row { margin-top:2px; align-items:center; }', + '.evolv-asset-tag-row > label { width:110px; white-space:nowrap; }', + '.evolv-asset-tag-row input[type=text] { width:auto !important; max-width:200px; min-width:140px; font-size:12px; padding:3px 6px; }', '@media (max-width:560px) {', ' .evolv-asset-chips { flex-direction:column; align-items:stretch; }', ' .evolv-asset-chip-sep { display:none; }', - ' .evolv-asset-chip { width:100%; }', + ' .evolv-asset-chip { width:100%; justify-content:flex-start; }', ' .evolv-asset-summary { grid-template-columns:1fr; }', ' .evolv-asset-curve { width:100%; }', '}' @@ -1020,7 +1026,7 @@ class AssetMenu {
- +
Not registered yet
diff --git a/src/menu/iconHelpers.js b/src/menu/iconHelpers.js index 55058a3..0663ed1 100644 --- a/src/menu/iconHelpers.js +++ b/src/menu/iconHelpers.js @@ -97,29 +97,95 @@ class IconHelpers { \`, + // Position icons — depict the PARENT equipment (pump volute + + // motor stub) plus a sensor marker located in the suction pipe + // (upstream), atop the equipment (atEquipment), or in the + // discharge pipe (downstream). Flow direction: left → right. upstream: \` \`, atEquipment: \` \`, downstream: \` \`, + // Output-format icons — used by the shared + // renderOutputFormatPicker helper so every node renders the + // process/json/csv/influxdb dropdowns with the same visuals. + outputProcess: \` + \`, + outputJson: \` + \`, + outputCsv: \` + \`, + outputInflux: \` + \`, distance: \`
. + const OUTPUT_FORMAT_ICONS = { + process: SVG.outputProcess, + json: SVG.outputJson, + csv: SVG.outputCsv, + influxdb: SVG.outputInflux, + }; + const OUTPUT_FORMAT_LABELS = { + process: 'Process', + json: 'JSON', + csv: 'CSV', + influxdb: 'Influx', + }; + function renderOutputFormatPicker(select, holder) { + renderSelectPicker(select, holder, OUTPUT_FORMAT_ICONS, OUTPUT_FORMAT_LABELS); + } + + // upgradeOutputFormatSelects: idempotent platform-wide upgrade. + // Scans the open editor dialog for the two canonical output-format + // selects and replaces each with the icon picker. Skips selects + // that are already upgraded (class evolv-native-hidden) or that + // already have a sibling picker placed by the node's HTML. + // Called from MenuManager's initEditor wrapper so every node + // inherits the picker without per-node template edits. + function upgradeOutputFormatSelects() { + const specs = [ + { id: 'node-input-processOutputFormat', aria: 'Process output format' }, + { id: 'node-input-dbaseOutputFormat', aria: 'Database output format' } + ]; + specs.forEach((spec) => { + const select = document.getElementById(spec.id); + if (!select) return; + if (select.classList && select.classList.contains('evolv-native-hidden')) return; + const parent = select.parentNode; + if (!parent) return; + // Skip if a sibling picker already exists (manual wiring). + const siblings = parent.children || []; + for (let i = 0; i < siblings.length; i += 1) { + const sib = siblings[i]; + if (sib !== select && sib.classList && sib.classList.contains('evolv-icon-picker')) return; + } + const holder = document.createElement('div'); + holder.className = 'evolv-icon-picker'; + holder.setAttribute('role', 'radiogroup'); + holder.setAttribute('aria-label', spec.aria); + parent.appendChild(holder); + renderOutputFormatPicker(select, holder); + }); + } + + return { SVG, renderSelectPicker, renderToggle, renderOutputFormatPicker, upgradeOutputFormatSelects }; })(); } `; diff --git a/src/menu/index.js b/src/menu/index.js index 01de199..d6a06ef 100644 --- a/src/menu/index.js +++ b/src/menu/index.js @@ -175,6 +175,18 @@ class MenuManager { } catch (${type}Error) { console.error('Error initializing ${type} menu for ${nodeName}:', ${type}Error); }`).join('')} + + // Platform-wide: upgrade output-format