flexdesk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/base.css +1484 -181
- package/css/flexdesk.css +1311 -18
- package/css/overrides.css +44 -0
- package/css/tokens.css +45 -0
- package/dist/charts.js +5 -3
- package/dist/charts.js.map +1 -1
- package/dist/{chunk-DVU44T77.js → chunk-ELXVW542.js} +196 -75
- package/dist/chunk-ELXVW542.js.map +7 -0
- package/dist/chunk-LH5TSOZW.js +1237 -0
- package/dist/chunk-LH5TSOZW.js.map +7 -0
- package/dist/{chunk-TLZUUFOE.js → chunk-O5OHMWBB.js} +10 -2
- package/dist/chunk-O5OHMWBB.js.map +7 -0
- package/dist/{chunk-CT4YXXLP.js → chunk-QIU5S2RU.js} +371 -73
- package/dist/chunk-QIU5S2RU.js.map +7 -0
- package/dist/chunk-QNQHQ24V.js +408 -0
- package/dist/chunk-QNQHQ24V.js.map +7 -0
- package/dist/{chunk-DRYCDMEG.js → chunk-XKDTIT4Q.js} +168 -12
- package/dist/chunk-XKDTIT4Q.js.map +7 -0
- package/dist/editor.js +3 -380
- package/dist/editor.js.map +3 -3
- package/dist/flexdesk.css +1311 -18
- package/dist/tiles.js +168 -41
- package/dist/tiles.js.map +2 -2
- package/dist/tokens.css +45 -0
- package/dist/widgets.js +44 -14
- package/dist/widgets.js.map +2 -2
- package/dist/wm.js +2983 -142
- package/dist/wm.js.map +4 -4
- package/package.json +3 -2
- package/src/charts/chart_types.js +167 -0
- package/src/charts/plotly_wrapper.js +178 -10
- package/src/editor/notebook_tab_bar.js +39 -3
- package/src/tiles/tile_base.js +143 -35
- package/src/tiles/tile_grid.js +52 -1
- package/src/tiling/command_palette.js +71 -18
- package/src/tiling/desktops.js +36 -12
- package/src/tiling/keymap.js +24 -4
- package/src/tiling/shell.js +135 -24
- package/src/tiling/tab_strip.js +184 -0
- package/src/tiling/tile_breadcrumb.js +34 -2
- package/src/tiling/tile_renderer.js +1386 -21
- package/src/tiling/tile_tab_menu.js +101 -0
- package/src/tiling/tile_tree.js +82 -0
- package/src/tiling/wm.js +2352 -74
- package/src/ui/components/action_dropdown.js +34 -3
- package/src/ui/components/autocomplete_field.js +65 -13
- package/src/ui/components/context_menu.js +79 -8
- package/src/ui/components/data_table.js +508 -84
- package/src/ui/components/managed_window.js +928 -36
- package/src/ui/components/modal.js +214 -8
- package/dist/chunk-CT4YXXLP.js.map +0 -7
- package/dist/chunk-DRYCDMEG.js.map +0 -7
- package/dist/chunk-DVU44T77.js.map +0 -7
- package/dist/chunk-TLZUUFOE.js.map +0 -7
- package/dist/chunk-UCJ2WD4D.js +0 -625
- package/dist/chunk-UCJ2WD4D.js.map +0 -7
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/charts/plotly_wrapper.js", "../src/charts/chart_types.js", "../src/charts/plot_config.js", "../src/charts/plot_popout_window.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Plotly.js Wrapper\n *\n * Provides lazy loading of Plotly.js and helper functions for chart operations.\n * Supports streaming updates via Plotly.extendTraces() and Plotly.react().\n */\n\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\n\n// Where Plotly lives is the CONSUMER's business, not the library's.\n//\n// This was `const PLOTLY_LOCAL = 'vendor/plotly/plotly-2.35.2.min.js'` \u2014 a\n// relative path into one particular application's directory tree. It happens to\n// work for EcoAgent and would 404 for anyone else, and the failure would arrive\n// as an empty chart with a console error, at runtime, only on the screens that\n// plot something.\n//\n// Plotly stays a PEER dependency: 4.4 MB that @flexdesk/charts refuses to bundle.\n//\n// There is NO DEFAULT. Leaving one in place would only have meant leaving\n// EcoAgent's exact versioned filename in the library \u2014 the same bug wearing a\n// setter \u2014 and it would fail for everyone else as an empty chart and a console\n// error, at runtime, on the screens that plot something.\n//\n// ensurePlotly() short-circuits when `window.Plotly` is already defined, which is\n// how EcoAgent works: it preloads Plotly with a <script> tag in index.html and\n// never reaches the loader below. A consumer that does not preload calls\n// setPlotlySource() instead. A consumer that does neither now gets told so.\nlet _plotlySrc = null;\n\n/** Point the loader at your copy of Plotly. Call before the first chart renders. */\nexport function setPlotlySource(src) {\n if (typeof src === 'string' && src) _plotlySrc = src;\n}\n\n// Loading promise for singleton pattern\nlet _plotlyLoadPromise = null;\n\n// Workarounds for Plotly.js 2.35.x running in Chromium-based pywebview.\nlet _plotlyPatchesInstalled = false;\nfunction _installPlotlyPatches() {\n if (_plotlyPatchesInstalled) return;\n _plotlyPatchesInstalled = true;\n\n // Plotly's internal mousemove handler assigns event.target which is\n // read-only in modern browsers. Replace the native getter with a\n // getter/setter pair so the assignment succeeds silently.\n const targetDesc = Object.getOwnPropertyDescriptor(Event.prototype, 'target');\n if (targetDesc && targetDesc.get && !targetDesc.set) {\n const origGetter = targetDesc.get;\n Object.defineProperty(Event.prototype, 'target', {\n configurable: true,\n enumerable: true,\n get() {\n return this._plotlyTarget ?? origGetter.call(this);\n },\n set(v) {\n this._plotlyTarget = v;\n }\n });\n }\n\n // Plotly calls getImageData() repeatedly on 2D canvases without the\n // willReadFrequently hint, triggering a Chromium performance warning.\n // Patch getContext to inject the hint for all 2D contexts.\n const _origGetContext = HTMLCanvasElement.prototype.getContext;\n HTMLCanvasElement.prototype.getContext = function (type, attrs) {\n if (type === '2d') {\n attrs = Object.assign({ willReadFrequently: true }, attrs);\n }\n return _origGetContext.call(this, type, attrs);\n };\n}\n\n// Run immediately on module import so the patches are active before any Plotly\n// chart is created (including during workspace hydration) \u2014 but ONLY in a DOM.\n//\n// Unguarded, this monkey-patched HTMLCanvasElement.prototype at module scope, so\n// `import '@flexdesk/charts'` threw `ReferenceError: HTMLCanvasElement is not defined`\n// the instant anything imported it outside a browser. That is the third module in\n// this library caught doing DOM work on import (see inline_renamer.js and\n// tooltip_service.js), and all three were found by the same test: one that does\n// nothing but import each entry point. A library whose entry point cannot be\n// imported without a DOM cannot be unit-tested, server-rendered, or loaded in a\n// worker.\nif (typeof HTMLCanvasElement !== 'undefined') {\n _installPlotlyPatches();\n}\n\n/**\n * Dark theme layout defaults matching EcoSim UI\n */\nexport const DARK_THEME_LAYOUT = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 11,\n color: '#cccccc'\n },\n margin: { l: 50, r: 20, t: 30, b: 40 },\n legend: {\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' }\n },\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n // Hover tooltip styling for dark theme\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 12,\n color: '#e0e0e0'\n }\n },\n // 3D scene defaults\n scene: {\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n zaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n bgcolor: 'rgba(0,0,0,0)'\n }\n};\n\n/**\n * Default Plotly config options\n */\nexport const DEFAULT_CONFIG = {\n responsive: true,\n displaylogo: false,\n displayModeBar: false, // Hide modebar completely\n scrollZoom: true, // Allow zoom with scroll wheel instead\n toImageButtonOptions: {\n format: 'png',\n filename: 'ecosim_chart',\n scale: 2\n }\n};\n\n/**\n * Load Plotly.js from CDN.\n * Uses singleton pattern to avoid multiple loads.\n * @returns {Promise<Plotly>} The Plotly library object\n */\nexport async function ensurePlotly() {\n // Already loaded\n if (typeof Plotly !== 'undefined') {\n return Plotly;\n }\n\n // Loading in progress\n if (_plotlyLoadPromise) {\n return _plotlyLoadPromise;\n }\n\n if (!_plotlySrc) {\n throw new Error(\n '[twm/charts] Plotly is not loaded and no source is configured. '\n + 'Either load Plotly yourself (a <script> tag that sets window.Plotly), '\n + 'or call setPlotlySource(\"/path/to/plotly.min.js\") before rendering a chart.');\n }\n\n // Start loading \u2014 temporarily hide AMD define so Plotly sets window.Plotly\n // instead of registering itself as an AMD module (conflicts with Monaco loader).\n _plotlyLoadPromise = new Promise((resolve, reject) => {\n const savedDefine = window.define;\n window.define = undefined;\n\n const script = document.createElement('script');\n script.src = _plotlySrc;\n script.async = true;\n\n script.onload = () => {\n window.define = savedDefine;\n if (typeof Plotly !== 'undefined') {\n console.log('[PlotlyWrapper] Plotly.js loaded successfully');\n resolve(Plotly);\n } else {\n reject(new Error('Plotly.js loaded but Plotly global not found'));\n }\n };\n\n script.onerror = () => {\n window.define = savedDefine;\n reject(new Error(`Failed to load Plotly.js from ${_plotlySrc} \u2014 `\n + 'call setPlotlySource() with the path to your copy.'));\n };\n\n document.head.appendChild(script);\n });\n\n return _plotlyLoadPromise;\n}\n\n/**\n * Create a new Plotly chart.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} data - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<HTMLElement>} The chart element\n */\nexport async function createChart(container, data, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n return Plotly.newPlot(container, data, mergedLayout, mergedConfig);\n}\n\n/**\n * Update chart data and layout efficiently.\n * Uses Plotly.react() which is optimized for updates.\n * @param {HTMLElement} container - Chart container\n * @param {Array} data - New trace data\n * @param {Object} layout - Layout updates\n */\nexport async function updateChart(container, data, layout = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n return Plotly.react(container, data, mergedLayout);\n}\n\n/**\n * Extend traces with new data points (for streaming).\n * More efficient than full update for appending data.\n * @param {HTMLElement} container - Chart container\n * @param {Object} update - Data to extend: { x: [[...]], y: [[...]] }\n * @param {Array<number>} traceIndices - Which traces to extend\n * @param {number} maxPoints - Maximum points to keep (optional)\n */\nexport async function extendTraces(container, update, traceIndices, maxPoints = null) {\n const Plotly = await ensurePlotly();\n\n if (maxPoints) {\n return Plotly.extendTraces(container, update, traceIndices, maxPoints);\n }\n return Plotly.extendTraces(container, update, traceIndices);\n}\n\n/**\n * Relayout chart (update layout only, no data change).\n * @param {HTMLElement} container - Chart container\n * @param {Object} layoutUpdate - Layout properties to update\n */\nexport async function relayout(container, layoutUpdate) {\n const Plotly = await ensurePlotly();\n return Plotly.relayout(container, layoutUpdate);\n}\n\n/**\n * Restyle traces (update trace properties without full redraw).\n * @param {HTMLElement} container - Chart container\n * @param {Object} styleUpdate - Style properties to update\n * @param {Array<number>} traceIndices - Which traces to update\n */\nexport async function restyle(container, styleUpdate, traceIndices) {\n const Plotly = await ensurePlotly();\n return Plotly.restyle(container, styleUpdate, traceIndices);\n}\n\n/**\n * Delete all traces and release resources.\n * @param {HTMLElement} container - Chart container\n */\nexport async function purge(container) {\n const Plotly = await ensurePlotly();\n return Plotly.purge(container);\n}\n\n/**\n * Check if container has a Plotly chart.\n * @param {HTMLElement} container - Container element\n * @returns {boolean}\n */\nexport function hasPlot(container) {\n return container && container._fullLayout !== undefined;\n}\n\n/**\n * Resize chart to fit container.\n * Call this when container size changes.\n * @param {HTMLElement} container - Chart container\n */\nexport async function resize(container) {\n const Plotly = await ensurePlotly();\n return Plotly.Plots.resize(container);\n}\n\n/**\n * Convert hex color to rgba.\n * @param {string} hex - Hex color code\n * @param {number} alpha - Alpha value (0-1)\n * @returns {string} rgba color string\n */\nexport function hexToRgba(hex, alpha = 1) {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return hex;\n const r = parseInt(result[1], 16);\n const g = parseInt(result[2], 16);\n const b = parseInt(result[3], 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n// Solarized theme colors matching legacy plot_node.js\nexport const COLOR_PALETTE = [\n '#268bd2', // Solarized Blue\n '#d33682', // Solarized Magenta\n '#cb4b16', // Solarized Orange\n '#2aa198', // Solarized Cyan\n '#6a5acd', // SlateBlue/Purple\n '#7a7d80', // Gray\n '#9fb6cf', // Gray-Blue\n];\n\n/**\n * Get color from palette by index.\n * @param {number} index - Series index\n * @returns {string} Color hex code\n */\nexport function getSeriesColor(index) {\n return COLOR_PALETTE[index % COLOR_PALETTE.length];\n}\n\n/**\n * Create a Plotly chart with deferred rendering support.\n * Handles zero-dimension containers by waiting for valid dimensions via ResizeObserver.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} traces - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<{element: HTMLElement, cleanup: Function}>} Chart element and cleanup function\n */\nexport async function createChartDeferred(container, traces, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n const w = container.offsetWidth;\n const h = container.offsetHeight;\n\n // Cleanup function to return\n let resizeObserver = null;\n const cleanup = () => {\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n };\n\n // If dimensions are valid, render immediately\n if (w > 0 && h > 0) {\n await Plotly.newPlot(container, traces, mergedLayout, mergedConfig);\n // Still set up resize observer for ongoing resizes\n resizeObserver = createRafResizeObserver(() => {\n if (hasPlot(container)) {\n Plotly.Plots.resize(container).catch(() => {});\n }\n });\n resizeObserver.observe(container);\n return { element: container, cleanup };\n }\n\n // Dimensions are zero - wait for valid dimensions via ResizeObserver\n return new Promise((resolve) => {\n let rendered = false;\n resizeObserver = createRafResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n if (width > 0 && height > 0) {\n if (!rendered) {\n rendered = true;\n Plotly.newPlot(container, traces, mergedLayout, mergedConfig).then(() => {\n resolve({ element: container, cleanup });\n }).catch(() => {\n resolve({ element: container, cleanup });\n });\n } else if (hasPlot(container)) {\n // Handle subsequent resizes\n Plotly.Plots.resize(container).catch(() => {});\n }\n }\n }\n });\n resizeObserver.observe(container);\n });\n}\n", "/**\n * Chart Types and Trace Configurations\n *\n * Defines trace configurations for Plotly.js and provides mapping\n * from Chart.js options to Plotly equivalents.\n */\n\nimport { getSeriesColor, hexToRgba } from './plotly_wrapper.js';\n\n/**\n * Available 2D chart types\n */\nexport const CHART_TYPES_2D = Object.freeze([\n { value: 'line', label: 'Line' },\n { value: 'bar', label: 'Bar' },\n { value: 'scatter', label: 'Scatter' },\n { value: 'area', label: 'Area' },\n { value: 'area-stacked', label: 'Area (Stacked %)' },\n { value: 'phase', label: 'Phase' },\n]);\n\n/**\n * Available 3D chart types\n */\nexport const CHART_TYPES_3D = Object.freeze([\n { value: 'scatter3d', label: '3D Scatter' },\n { value: 'line3d', label: '3D Line' },\n { value: 'surface', label: '3D Surface' },\n]);\n\n/**\n * All chart types combined\n */\nexport const ALL_CHART_TYPES = Object.freeze([...CHART_TYPES_2D, ...CHART_TYPES_3D]);\n\n/**\n * Check if chart type is 3D\n * @param {string} chartType\n * @returns {boolean}\n */\nexport function is3DChart(chartType) {\n return ['scatter3d', 'line3d', 'surface'].includes(chartType);\n}\n\n/**\n * Line style mapping (Chart.js borderDash to Plotly dash)\n */\nconst LINE_DASH_MAP = {\n solid: 'solid',\n dashed: 'dash',\n dotted: 'dot',\n};\n\n/**\n * Interpolation mapping (Chart.js to Plotly line shape)\n */\nconst INTERPOLATION_MAP = {\n linear: 'linear',\n step: 'hv', // horizontal-vertical step\n cubic: 'spline', // smooth spline\n auto: 'linear',\n};\n\n/**\n * Build a Plotly trace from series configuration.\n * @param {Object} options\n * @param {string} options.chartType - Chart type (line, bar, scatter, area, scatter3d, etc.)\n * @param {Array} options.x - X-axis data\n * @param {Array} options.y - Y-axis data\n * @param {Array} [options.z] - Z-axis data (for 3D charts)\n * @param {string} options.name - Series name/label\n * @param {string} [options.color] - Series color (hex)\n * @param {number} [options.lineWidth] - Line width in pixels\n * @param {string} [options.lineStyle] - Line style: solid, dashed, dotted\n * @param {string} [options.interpolation] - Interpolation: linear, step, cubic\n * @param {string} [options.yAxisId] - Y-axis identifier (y, y2, y3, etc.)\n * @param {boolean} [options.showMarkers] - Show data point markers\n * @param {number} [options.seriesIndex] - Index for default color selection\n * @returns {Object} Plotly trace object\n */\nexport function buildTrace(options) {\n const {\n chartType = 'line',\n x = [],\n y = [],\n z = null,\n name = 'Series',\n color = null,\n lineWidth = 2,\n lineStyle = 'solid',\n interpolation = 'linear',\n yAxisId = 'y',\n showMarkers = false,\n seriesIndex = 0,\n stackGroup = null,\n } = options;\n\n const seriesColor = color || getSeriesColor(seriesIndex);\n\n // Determine Plotly trace type and mode\n let plotlyType, mode;\n switch (chartType) {\n case 'line':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'scatter':\n plotlyType = 'scatter';\n mode = 'markers';\n break;\n case 'area':\n case 'area-stacked':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'phase':\n plotlyType = 'scatter';\n mode = 'lines+markers';\n break;\n case 'bar':\n plotlyType = 'bar';\n mode = undefined;\n break;\n case 'scatter3d':\n plotlyType = 'scatter3d';\n mode = 'markers';\n break;\n case 'line3d':\n plotlyType = 'scatter3d';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'surface':\n plotlyType = 'surface';\n mode = undefined;\n break;\n default:\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n }\n\n // Build base trace\n const trace = {\n type: plotlyType,\n name,\n x,\n y,\n };\n\n // Add mode if applicable\n if (mode) {\n trace.mode = mode;\n }\n\n // Add z-axis data for 3D charts\n if (z && is3DChart(chartType)) {\n // Surface charts require z to be a 2D array\n // If z is 1D (time series data), use mesh3d with Delaunay triangulation\n if (chartType === 'surface') {\n const zIs2D = Array.isArray(z) && z.length > 0 && Array.isArray(z[0]);\n if (zIs2D) {\n trace.z = z;\n } else {\n // Use mesh3d with Delaunay triangulation for 1D scattered points\n console.info('[chart_types] Surface chart with 1D z data - using mesh3d with Delaunay triangulation');\n trace.type = 'mesh3d';\n trace.x = x;\n trace.y = y;\n trace.z = z;\n trace.alphahull = 0; // Delaunay triangulation (convex hull = -1, 0 = Delaunay)\n trace.opacity = 0.8;\n trace.color = seriesColor;\n trace.flatshading = true;\n trace.lighting = {\n ambient: 0.6,\n diffuse: 0.5,\n specular: 0.2,\n };\n // Skip surface-specific config below\n return trace;\n }\n } else {\n trace.z = z;\n }\n }\n\n // Phase chart: line with small markers\n if (chartType === 'phase') {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n };\n trace.marker = {\n color: seriesColor,\n size: 3,\n };\n return trace;\n }\n\n // Line configuration (for line/area charts)\n if (['line', 'area', 'area-stacked', 'line3d'].includes(chartType)) {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n shape: INTERPOLATION_MAP[interpolation] || 'linear',\n };\n }\n\n // Marker configuration\n if (['scatter', 'scatter3d'].includes(chartType) || showMarkers) {\n trace.marker = {\n color: seriesColor,\n size: chartType === 'scatter3d' ? 4 : 6,\n };\n }\n\n // Normalized stacked area: each Y-axis is its own stack group, each summing to 1.\n if (chartType === 'area-stacked') {\n trace.stackgroup = yAxisId;\n trace.groupnorm = 'fraction';\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n // Fill for area charts (non-stacked)\n else if (chartType === 'area' && !stackGroup) {\n trace.fill = 'tozeroy';\n trace.fillcolor = hexToRgba(seriesColor, 0.3);\n }\n // Stacked area via explicit stackGroup on any chart type\n else if (stackGroup) {\n trace.stackgroup = stackGroup;\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n\n // Bar color\n if (chartType === 'bar') {\n trace.marker = {\n color: seriesColor,\n };\n }\n\n // Surface colorscale\n if (chartType === 'surface') {\n trace.colorscale = 'Viridis';\n trace.showscale = true;\n }\n\n // Y-axis assignment (for multi-axis support)\n if (!is3DChart(chartType) && yAxisId && yAxisId !== 'y') {\n trace.yaxis = yAxisId;\n }\n\n return trace;\n}\n\n/**\n * Build layout for Y-axis based on configuration.\n * @param {Object} options\n * @param {string} options.axisId - Axis identifier (y, y2, y3, etc.)\n * @param {string} [options.title] - Axis title\n * @param {string} [options.position] - Axis position: left or right\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @param {number} [options.step] - Tick step size\n * @param {boolean} [options.showGrid] - Show grid lines\n * @param {number|null} [options.axisPosition] - Explicit position in normalized coords (0-1), null for default\n * @returns {Object} Plotly axis layout object\n */\nexport function buildYAxisLayout(options) {\n const {\n axisId = 'yaxis',\n title = '',\n position = 'left',\n scaleType = 'linear',\n min = null,\n max = null,\n step = null,\n showGrid = true,\n axisPosition = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n side: position,\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n showgrid: showGrid,\n automargin: true, // Auto-expand margin for tick labels\n };\n\n // Set range if min/max provided.\n // Both bounds: fixed range (autorange off).\n // One-sided: use autorangeoptions so Plotly auto-ranges within data but respects the cap/floor.\n // Plotly does not accept null in a range array \u2014 [null, max] silently sets the lower bound to 0.\n if (min !== null && max !== null) {\n layout.autorange = false;\n layout.range = [min, max];\n } else if (min !== null || max !== null) {\n layout.autorange = true;\n layout.autorangeoptions = {};\n if (min !== null) layout.autorangeoptions.minallowed = min;\n if (max !== null) layout.autorangeoptions.maxallowed = max;\n }\n\n // Set tick step if provided\n if (step !== null && step > 0) {\n layout.dtick = step;\n }\n\n // For secondary axes, overlay on the first y-axis\n if (axisId !== 'yaxis') {\n layout.overlaying = 'y';\n layout.anchor = 'free';\n\n // Use explicit position if provided (for proper multi-axis layout)\n // axisPosition is in normalized figure coordinates (0-1)\n if (axisPosition !== null) {\n layout.position = axisPosition;\n } else {\n // Fallback: position at domain edge (0 for left, 1 for right)\n layout.position = position === 'left' ? 0 : 1;\n }\n }\n\n return layout;\n}\n\n/**\n * Build X-axis layout.\n * @param {Object} options\n * @param {string} [options.title] - Axis title\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @returns {Object} Plotly xaxis layout object\n */\nexport function buildXAxisLayout(options) {\n const {\n title = 'Time',\n scaleType = 'linear',\n min = null,\n max = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n automargin: true,\n };\n\n if (min !== null || max !== null) {\n layout.range = [min, max];\n }\n\n return layout;\n}\n\n/**\n * Build 3D scene layout.\n * @param {Object} options\n * @param {string} [options.xTitle] - X-axis title\n * @param {string} [options.yTitle] - Y-axis title\n * @param {string} [options.zTitle] - Z-axis title\n * @param {string} [options.zScale] - Z-axis scale type: 'linear' or 'log'\n * @param {number} [options.zMin] - Z-axis minimum value\n * @param {number} [options.zMax] - Z-axis maximum value\n * @param {number} [options.zStep] - Z-axis tick step size\n * @returns {Object} Plotly scene layout object\n */\nexport function build3DSceneLayout(options) {\n const {\n xTitle = 'X',\n yTitle = 'Y',\n zTitle = 'Z',\n zScale = 'linear',\n zMin = null,\n zMax = null,\n zStep = null,\n } = options;\n\n const zaxis = {\n title: { text: zTitle },\n type: zScale === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n };\n\n // Set range if min/max provided\n if (zMin !== null || zMax !== null) {\n zaxis.range = [zMin, zMax];\n }\n\n // Set tick step if provided\n if (zStep !== null && zStep > 0) {\n zaxis.dtick = zStep;\n }\n\n return {\n xaxis: {\n title: { text: xTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n yaxis: {\n title: { text: yTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n zaxis,\n bgcolor: 'rgba(0,0,0,0)',\n };\n}\n\n/**\n * Build legend layout.\n * @param {string} position - Legend position: top, bottom, left, right, hidden\n * @returns {Object} Plotly legend layout\n */\nexport function buildLegendLayout(position) {\n if (position === 'hidden') {\n return { showlegend: false };\n }\n\n const baseLayout = {\n showlegend: true,\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' },\n };\n\n switch (position) {\n case 'top':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: 1.1,\n yanchor: 'bottom',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'bottom':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: -0.15,\n yanchor: 'top',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'left':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: -0.15,\n xanchor: 'right',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n case 'right':\n default:\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: 1.02,\n xanchor: 'left',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n }\n}\n\n/**\n * Build Plotly layout shapes + annotations for reference lines and shaded x-bands.\n *\n * @param {Object} opts\n * @param {Array<{yAxisId?:string, value:number, label?:string, color?:string, lineStyle?:string, lineWidth?:number, labelX?:number}>} [opts.referenceLines]\n * Horizontal threshold lines drawn across the plot, anchored to a specific Y axis.\n * `yAxisId` matches an axis id in sp.yAxes[].id; omitted \u2192 first axis.\n * @param {Array<{x0:number, x1:number, label?:string, color?:string, opacity?:number, labelY?:number, labelColor?:string}>} [opts.shadedBands]\n * Vertical stripes (rectangles spanning full y range) to mark policy/recession periods.\n * @param {Object<string,string>} [opts.yRefByAxisId]\n * Mapping from subplot yAxes[i].id \u2192 Plotly yref ('y', 'y2', ...).\n * @returns {{shapes: Array, annotations: Array}}\n */\nexport function buildOverlayShapes(opts = {}) {\n const { referenceLines = [], shadedBands = [], yRefByAxisId = {} } = opts;\n const shapes = [];\n const annotations = [];\n const dashMap = { solid: 'solid', dashed: 'dash', dotted: 'dot', dashdot: 'dashdot' };\n\n for (const band of shadedBands) {\n if (band.x0 == null || band.x1 == null) continue;\n shapes.push({\n type: 'rect',\n xref: 'x',\n yref: 'paper',\n x0: band.x0,\n x1: band.x1,\n y0: 0,\n y1: 1,\n fillcolor: band.color || 'rgba(255, 200, 0, 0.08)',\n line: { width: 0 },\n opacity: band.opacity ?? 1,\n layer: 'below',\n });\n if (band.label) {\n annotations.push({\n x: (band.x0 + band.x1) / 2,\n y: band.labelY ?? 1.0,\n xref: 'x',\n yref: 'paper',\n text: band.label,\n showarrow: false,\n font: { size: 9, color: band.labelColor || 'rgba(255,255,255,0.55)' },\n xanchor: 'center',\n yanchor: 'bottom',\n });\n }\n }\n\n const firstYRef = Object.values(yRefByAxisId)[0] || 'y';\n for (const ref of referenceLines) {\n if (ref.value == null || !Number.isFinite(ref.value)) continue;\n const yRef = (ref.yAxisId && yRefByAxisId[ref.yAxisId]) || firstYRef;\n const color = ref.color || 'rgba(255, 120, 120, 0.75)';\n shapes.push({\n type: 'line',\n xref: 'paper',\n yref: yRef,\n x0: 0,\n x1: 1,\n y0: ref.value,\n y1: ref.value,\n line: {\n color,\n width: ref.lineWidth ?? 1.5,\n dash: dashMap[ref.lineStyle || 'dashed'] || 'dash',\n },\n layer: 'above',\n });\n if (ref.label) {\n annotations.push({\n x: ref.labelX ?? 0.015,\n y: ref.value,\n xref: 'paper',\n yref: yRef,\n text: ref.label,\n showarrow: false,\n font: { size: 10, color },\n xanchor: 'left',\n yanchor: 'bottom',\n bgcolor: 'rgba(20,22,26,0.6)',\n borderpad: 2,\n });\n }\n }\n\n return { shapes, annotations };\n}\n\n/**\n * Create a fan chart trace with confidence bands.\n * @param {Object} options\n * @param {Array} options.x - X-axis data (time)\n * @param {Array} options.upper - Upper bound data\n * @param {Array} options.lower - Lower bound data\n * @param {string} options.color - Band color\n * @param {number} options.opacity - Fill opacity\n * @param {string} [options.name] - Band name for legend\n * @returns {Array} Array of two traces (lower bound + fill to upper)\n */\nexport function buildFanBandTraces(options) {\n const { x, upper, lower, color, opacity = 0.2, name = '' } = options;\n\n // Lower bound line (invisible, for fill reference)\n const lowerTrace = {\n type: 'scatter',\n x,\n y: lower,\n mode: 'lines',\n line: { width: 0 },\n showlegend: false,\n hoverinfo: 'skip',\n };\n\n // Upper bound with fill to lower\n const upperTrace = {\n type: 'scatter',\n x,\n y: upper,\n mode: 'lines',\n line: { width: 0 },\n fill: 'tonexty',\n fillcolor: hexToRgba(color, opacity),\n name: name || `${(opacity * 100).toFixed(0)}% Band`,\n showlegend: !!name,\n };\n\n return [lowerTrace, upperTrace];\n}\n\n/**\n * Create a histogram trace.\n * @param {Object} options\n * @param {Array} options.x - Data values\n * @param {number} options.nbins - Number of bins\n * @param {string} options.color - Bar color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly histogram trace\n */\nexport function buildHistogramTrace(options) {\n const { x, nbins = 20, color, name = 'Distribution' } = options;\n\n return {\n type: 'histogram',\n x,\n nbinsx: nbins,\n marker: { color },\n name,\n };\n}\n\n/**\n * Create a box plot trace.\n * @param {Object} options\n * @param {Array} options.y - Data values\n * @param {string} [options.x] - Category/time label\n * @param {string} options.color - Box color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly box trace\n */\nexport function buildBoxTrace(options) {\n const { y, x = null, color, name = '' } = options;\n\n const trace = {\n type: 'box',\n y,\n marker: { color },\n name,\n boxpoints: false, // Don't show individual points\n };\n\n if (x !== null) {\n trace.x = Array.isArray(x) ? x : [x];\n }\n\n return trace;\n}\n\n/**\n * Create a heatmap trace.\n * @param {Object} options\n * @param {Array} options.z - 2D array of values\n * @param {Array} [options.x] - X labels\n * @param {Array} [options.y] - Y labels\n * @param {string} [options.colorscale] - Plotly colorscale name\n * @returns {Object} Plotly heatmap trace\n */\nexport function buildHeatmapTrace(options) {\n const { z, x = null, y = null, colorscale = 'RdBu' } = options;\n\n const trace = {\n type: 'heatmap',\n z,\n colorscale,\n showscale: true,\n };\n\n if (x) trace.x = x;\n if (y) trace.y = y;\n\n return trace;\n}\n", "/**\n * plot_config.js \u2014 the shape of a plot, independent of what is being plotted.\n *\n * Subplot grid layouts, the default subplot, the legacy-format migration, and the\n * NaN strategies (gap / zero / hold / interpolate). Not one line of it knows what\n * an economy is.\n *\n * It lived in ui/js/notebook/cells/plot_cell.js \u2014 an EcoAgent notebook cell with\n * 60 domain words in it \u2014 and that single import was the only thing keeping the\n * plot windows out of @flexdesk/charts. Five modules imported these helpers THROUGH the\n * cell, which is how you end up with a chart library that depends on a notebook.\n *\n * plot_cell.js re-exports everything here, so its existing importers are unchanged.\n */\n\nimport { getSeriesColor } from './plotly_wrapper.js';\n\n\nlet _uid = 0;\nfunction uid(prefix = 'p') { return `${prefix}-${++_uid}-${Date.now().toString(36)}`; }\n\n/**\n * Apply NaN handling strategy to a data array.\n * @param {number[]} data\n * @param {'gap'|'zero'|'hold'|'interpolate'} strategy\n * @param {number[]} xData \u2014 for interpolation\n * @returns {Array}\n */\nfunction applyNanHandling(data, strategy, xData) {\n const isMissing = (v) => v === null || v === undefined || (typeof v === 'number' && !Number.isFinite(v));\n\n if (strategy === 'zero') return data.map(v => isMissing(v) ? 0 : v);\n\n if (strategy === 'hold') {\n const result = [];\n let last = null;\n for (const v of data) {\n if (isMissing(v)) result.push(last);\n else { last = v; result.push(v); }\n }\n return result;\n }\n\n if (strategy === 'interpolate') {\n const result = [...data];\n for (let i = 0; i < result.length; i++) {\n if (!isMissing(result[i])) continue;\n let left = -1, right = -1;\n for (let j = i - 1; j >= 0; j--) { if (!isMissing(result[j])) { left = j; break; } }\n for (let j = i + 1; j < result.length; j++) { if (!isMissing(result[j])) { right = j; break; } }\n if (left >= 0 && right >= 0 && xData) {\n const frac = (xData[i] - xData[left]) / (xData[right] - xData[left]);\n result[i] = result[left] + frac * (result[right] - result[left]);\n } else if (left >= 0) {\n result[i] = result[left];\n } else if (right >= 0) {\n result[i] = result[right];\n } else {\n result[i] = null;\n }\n }\n return result;\n }\n\n // 'gap' (default) \u2014 replace with null for Plotly gap rendering\n return data.map(v => isMissing(v) ? null : v);\n}\n\n// \u2500\u2500\u2500 Layout templates (matching figure_cell.js) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PLOT_LAYOUTS = Object.freeze({\n '1x1': { label: 'Single', slots: 1, grid: { columns: '1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }] },\n '1x2': { label: 'Side by side', slots: 2, grid: { columns: '1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }] },\n '2x1': { label: 'Stacked', slots: 2, grid: { columns: '1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '2/1/3/2' }] },\n '2x2': { label: '2\\u00d72 Grid', slots: 4, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/2' }, { slot: 3, gridArea: '2/2/3/3' }] },\n '1x3': { label: 'Three columns', slots: 3, grid: { columns: '1fr 1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '1/3/2/4' }] },\n 'wide-top': { label: '1 + 2', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/3' }, { slot: 1, gridArea: '2/1/3/2' }, { slot: 2, gridArea: '2/2/3/3' }] },\n 'wide-bottom': { label: '2 + 1', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/3' }] },\n});\n\nfunction makeDefaultSubplot(index) {\n return {\n id: uid('sp'),\n displayName: '',\n chartType: 'line',\n legendPosition: 'hidden',\n interpolation: 'linear',\n nanHandling: 'gap',\n showDataPoints: false,\n showHpTrend: false,\n showHpCycle: false,\n hpLambda: 1600,\n xAxis: { useTime: true, variable: '' },\n zAxis: null,\n yAxes: [{\n id: uid('y'),\n label: '',\n scale: 'linear',\n position: 'left',\n min: null,\n max: null,\n step: null,\n series: [],\n }],\n };\n}\n\nfunction migrateData(data) {\n // Already in multi-layout format\n if (data?.layout && Array.isArray(data?.subplots)) {\n // Migrate caption \u2192 description (old field name)\n if ('caption' in data && !('description' in data)) {\n data.description = data.caption;\n data.caption = '';\n }\n return data;\n }\n\n // Migrate legacy single-chart format \u2192 multi-layout with one subplot\n const legacySingle = migrateSingleChart(data);\n return {\n layout: '1x1',\n subplots: [{ id: uid('sp'), ...legacySingle }],\n caption: '',\n description: data?.caption ?? data?.description ?? '',\n doc: data?.doc ?? '',\n };\n}\n\n/** Migrate legacy flat series[]/variables[] to yAxes[] single-chart format. */\nfunction migrateSingleChart(data) {\n if (data?.yAxes) {\n return {\n displayName: data.displayName ?? '',\n chartType: data.chartType ?? 'line',\n legendPosition: data.legendPosition ?? 'hidden',\n interpolation: data.interpolation ?? 'linear',\n nanHandling: data.nanHandling ?? 'gap',\n showDataPoints: data.showDataPoints ?? false,\n yAxes: data.yAxes,\n };\n }\n\n const series = data?.series ?? data?.variables?.map((v, i) => ({\n variable: v, label: '', color: getSeriesColor(i),\n })) ?? [];\n\n return {\n displayName: data?.title ?? data?.displayName ?? '',\n chartType: data?.chartType ?? data?.widgetType ?? 'line',\n legendPosition: data?.legendPosition ?? 'hidden',\n interpolation: data?.interpolation ?? 'linear',\n nanHandling: data?.nanHandling ?? 'gap',\n showDataPoints: data?.showDataPoints ?? false,\n yAxes: [{\n id: uid('y'),\n label: data?.yLabel ?? '',\n scale: 'linear',\n position: 'left',\n min: null,\n max: null,\n series: series.map((s, i) => ({\n id: s.id ?? uid('s'),\n variable: s.variable ?? '',\n label: s.label ?? '',\n color: s.color ?? getSeriesColor(i),\n lineWidth: s.lineWidth ?? 2,\n lineStyle: s.lineStyle ?? 'solid',\n stackGroup: s.stackGroup ?? null,\n ...(s.overlay ? { overlay: s.overlay } : {}),\n })),\n }],\n };\n}\n\nexport { uid, applyNanHandling, PLOT_LAYOUTS, makeDefaultSubplot, migrateData, migrateSingleChart };\n", "/**\n * Plot Popout Window\n *\n * Opens a plot in a separate draggable/resizable ManagedWindow with two tabs:\n * - Plot tab: Interactive Plotly chart grid with modebar controls\n * - Data tab: Table showing all series using the unified DataTable component\n *\n * Uses the PlotCell data model (multi-layout subplots) as its canonical format.\n * All plot window contexts (notebook, dashboard, documentation) use this single\n * implementation.\n *\n * Features:\n * - Multi-subplot grid layouts (1x1, 1x2, 2x1, 2x2, 1x3, wide-top, wide-bottom)\n * - Series visibility toggle panel\n * - Zoom/pan toolbar with zoom in/out, autoscale, reset\n * - PyWebView integration for file downloads (CSV, PNG)\n * - NotificationCenter integration for user feedback\n * - Live streaming updates while the data source is running\n * - HP filter trend/cycle decomposition\n * - ETL actuals overlay support\n */\n\nimport { ManagedWindow } from '../ui/components/managed_window.js';\nimport { DataTable } from '../ui/components/data_table.js';\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\nimport {\n ensurePlotly,\n purge,\n getSeriesColor,\n} from './plotly_wrapper.js';\nimport {\n buildTrace,\n buildYAxisLayout,\n buildLegendLayout,\n buildOverlayShapes,\n} from './chart_types.js';\nimport {\n PLOT_LAYOUTS,\n migrateData,\n applyNanHandling,\n} from './plot_config.js';\n\nexport class PlotPopoutWindow {\n /**\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js). Its `dialogs`\n * capability backs Export PNG/CSV; absent => Blob download fallback.\n * @param {Function} [options.onClose] - Called when window closes\n * @param {Object} [options.actuals] - ETL overlay data { seriesId: { years, values } }\n * @param {Function} [options.configRenderer] - (container) => void \u2014 renders config panel\n */\n constructor({ id, title, plotConfig, getResults, services, host, onClose, actuals,\n configRenderer,\n // The window used to listen for 'simulation:run:completed' and tell\n // the user to \"run simulation first\". A chart window does not know\n // that its data comes from a simulation; the app that opens it does.\n refreshEvent = 'data:changed',\n emptyMessage = 'No data yet.',\n tableEmptyMessage = 'No data yet.' }) {\n this._id = id;\n this._title = title || 'Plot';\n this._plotConfig = migrateData(plotConfig);\n this._getResults = getResults;\n this._services = services;\n this._host = host || null;\n this._onClose = onClose ?? (() => {});\n this._actuals = actuals ?? null;\n this._configRenderer = configRenderer ?? null;\n this.refreshEvent = refreshEvent;\n // TWO messages, not one. The chart says \"No data \u2014 run simulation first.\"\n // and the data table underneath says \"Run simulation to see data\". Folding\n // them into a single option would have quietly rewritten one of them, which\n // is the kind of change a pixel gate catches only if a captured view happens\n // to be showing an empty plot.\n this.emptyMessage = emptyMessage;\n this.tableEmptyMessage = tableEmptyMessage;\n\n this._window = null;\n this._contentEl = null;\n this._chartDivs = [];\n this._gridEl = null;\n this._activeTab = 'plot';\n this._eventDisposers = [];\n this._resizeObserver = null;\n this._chartCreated = false;\n this._lastResults = null;\n\n // Data table\n this._dataTable = null;\n this._dataTableContainer = null;\n this._tableHeaders = [];\n this._tableRows = [];\n\n // DOM refs\n this._plotTab = null;\n this._dataTab = null;\n this._configTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._configContent = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n\n // Series visibility toggle\n this._hiddenSeries = new Set();\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._outsideClickHandler = null;\n\n this._renderPending = false;\n\n // Live-update toggle: when true, window re-renders on streaming events\n this._liveUpdate = true;\n this._liveBtn = null;\n }\n\n get isVisible() { return this._window?.isVisible ?? false; }\n\n async show() {\n if (this._window?.isVisible) {\n this._window.bringToFront();\n return;\n }\n\n await ensurePlotly();\n this.#createWindow();\n this.#subscribeEvents();\n this.#setupResizeObserver();\n await this.#render();\n }\n\n bringToFront() { this._window?.bringToFront?.(); }\n\n close() { this._window?.close?.(); }\n\n /** Update plot config and re-render. */\n updateConfig(plotConfig) {\n this._plotConfig = migrateData(plotConfig);\n this.#buildSubplotGrid();\n this.#scheduleRender();\n }\n\n /** Update actuals overlay data and re-render. */\n setActuals(actuals) {\n this._actuals = actuals;\n this.#scheduleRender();\n }\n\n // \u2500\u2500 Window creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #createWindow() {\n this._contentEl = this.#buildContent();\n\n this._window = new ManagedWindow({\n id: `plot-window-${this._id}`,\n title: this._title,\n icon: 'monitoring',\n content: this._contentEl,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: () => { this.#dispose(); this._onClose(); },\n });\n\n this._window.show();\n }\n\n #buildContent() {\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n this._plotTab = document.createElement('button');\n this._plotTab.className = 'twm-code-tab active';\n this._plotTab.type = 'button';\n this._plotTab.textContent = 'Plot';\n this._plotTab.addEventListener('click', () => this.#switchTab('plot'));\n\n this._dataTab = document.createElement('button');\n this._dataTab.className = 'twm-code-tab';\n this._dataTab.type = 'button';\n this._dataTab.textContent = 'Data';\n this._dataTab.addEventListener('click', () => this.#switchTab('data'));\n\n tabs.appendChild(this._plotTab);\n tabs.appendChild(this._dataTab);\n\n if (this._configRenderer) {\n this._configTab = document.createElement('button');\n this._configTab.className = 'twm-code-tab';\n this._configTab.type = 'button';\n this._configTab.textContent = 'Config';\n this._configTab.addEventListener('click', () => this.#switchTab('config'));\n tabs.appendChild(this._configTab);\n }\n\n // Toolbar (visible when Plot tab is active)\n this._toolbarActions = document.createElement('div');\n this._toolbarActions.className = 'twm-plot-window-toolbar';\n\n // Drag mode group\n const dragGroup = this.#toolbarGroup();\n this._zoomBtn = this.#toolbarBtn('search', 'Zoom', () => this.#setDragMode('zoom'));\n this._zoomBtn.classList.add('twm-is-active');\n this._panBtn = this.#toolbarBtn('pan_tool', 'Pan', () => this.#setDragMode('pan'));\n dragGroup.appendChild(this._zoomBtn);\n dragGroup.appendChild(this._panBtn);\n this._toolbarActions.appendChild(dragGroup);\n\n // Zoom control group\n const zoomGroup = this.#toolbarGroup();\n zoomGroup.appendChild(this.#toolbarBtn('zoom_in', 'Zoom in', () => this.#zoom(0.5)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out', 'Zoom out', () => this.#zoom(2)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out_map', 'Autoscale', () => this.#autoscale()));\n zoomGroup.appendChild(this.#toolbarBtn('home', 'Reset axes', () => this.#autoscale()));\n this._toolbarActions.appendChild(zoomGroup);\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n this._toolbarActions.appendChild(spacer);\n\n // Action buttons group\n const actionsGroup = this.#toolbarGroup();\n\n // Live-update toggle\n this._liveBtn = this.#toolbarBtn('stream', 'Live update \u2014 click to lock', () => this.#toggleLiveUpdate());\n this._liveBtn.classList.add('twm-is-active');\n actionsGroup.appendChild(this._liveBtn);\n\n // Series visibility toggle\n const toggleSeriesBtn = this.#toolbarBtn('visibility', 'Toggle series visibility', () => this.#toggleSeriesPanel());\n this._seriesToggleBtn = toggleSeriesBtn;\n actionsGroup.appendChild(toggleSeriesBtn);\n\n // Download PNG\n actionsGroup.appendChild(this.#toolbarBtn('image', 'Download plot as PNG', () => this.#downloadPNG()));\n\n // Download CSV\n actionsGroup.appendChild(this.#toolbarBtn('download', 'Download data as CSV', () => this.#downloadCSV()));\n\n this._toolbarActions.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(this._toolbarActions);\n\n // Tab content area\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n // Plot tab content\n this._plotContent = document.createElement('div');\n this._plotContent.className = 'twm-plot-tab-content active';\n this._plotContent.setAttribute('data-tab', 'plot');\n this._plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n this._gridEl = document.createElement('div');\n this._gridEl.className = 'twm-plot-window-chart';\n this._plotContent.appendChild(this._gridEl);\n\n this.#buildSubplotGrid();\n\n // Data tab content\n this._dataContent = document.createElement('div');\n this._dataContent.className = 'twm-plot-tab-content';\n this._dataContent.setAttribute('data-tab', 'data');\n this._dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n this._dataTableContainer = document.createElement('div');\n this._dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n this._dataContent.appendChild(this._dataTableContainer);\n\n content.appendChild(this._plotContent);\n content.appendChild(this._dataContent);\n\n // Config tab content (optional)\n if (this._configRenderer) {\n this._configContent = document.createElement('div');\n this._configContent.className = 'twm-plot-tab-content';\n this._configContent.setAttribute('data-tab', 'config');\n this._configContent.style.cssText = 'display:none; flex-direction:column; overflow:auto; padding:8px 12px;';\n this._configRenderer(this._configContent);\n content.appendChild(this._configContent);\n }\n\n // Series visibility dropdown panel (initially hidden)\n this._seriesTogglePanel = document.createElement('div');\n this._seriesTogglePanel.className = 'twm-plot-series-toggle-panel';\n this._seriesTogglePanel.style.display = 'none';\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n container.appendChild(this._seriesTogglePanel);\n\n return container;\n }\n\n // \u2500\u2500 Subplot grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #buildSubplotGrid() {\n if (!this._gridEl) return;\n\n // Purge existing charts\n for (const div of this._chartDivs) {\n if (div && window.Plotly) {\n try { purge(div); } catch (_) {}\n }\n }\n this._gridEl.innerHTML = '';\n this._chartDivs = [];\n\n const tmpl = PLOT_LAYOUTS[this._plotConfig.layout] || PLOT_LAYOUTS['1x1'];\n this._gridEl.style.display = 'grid';\n this._gridEl.style.gridTemplateColumns = tmpl.grid.columns;\n this._gridEl.style.gridTemplateRows = tmpl.grid.rows;\n this._gridEl.style.gap = '4px';\n this._gridEl.style.height = '100%';\n this._gridEl.style.width = '100%';\n\n for (let i = 0; i < tmpl.slots; i++) {\n const div = document.createElement('div');\n div.className = 'plot-tile-chart';\n div.style.gridArea = tmpl.areas[i].gridArea;\n div.style.minHeight = '0';\n this._gridEl.appendChild(div);\n this._chartDivs.push(div);\n }\n\n this._chartCreated = false;\n }\n\n // \u2500\u2500 Toolbar helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toolbarGroup() {\n const g = document.createElement('div');\n g.className = 'twm-plot-window-toolbar__group';\n return g;\n }\n\n #toolbarBtn(icon, tooltip, onClick) {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n if (onClick) btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n }\n\n // \u2500\u2500 Plotly toolbar actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #setDragMode(mode) {\n if (!this._chartCreated) return;\n for (const div of this._chartDivs) {\n if (div._fullLayout) {\n window.Plotly.relayout(div, { dragmode: mode }).catch(() => {});\n }\n }\n this._zoomBtn?.classList.toggle('twm-is-active', mode === 'zoom');\n this._panBtn?.classList.toggle('twm-is-active', mode === 'pan');\n }\n\n #zoom(factor) {\n for (const div of this._chartDivs) {\n if (!div._fullLayout) continue;\n const xa = div._fullLayout.xaxis;\n const ya = div._fullLayout.yaxis;\n if (!xa || !ya) continue;\n\n const xr = xa.range;\n const yr = ya.range;\n const xMid = (xr[0] + xr[1]) / 2;\n const yMid = (yr[0] + yr[1]) / 2;\n const xHalf = (xr[1] - xr[0]) / 2 * factor;\n const yHalf = (yr[1] - yr[0]) / 2 * factor;\n\n window.Plotly.relayout(div, {\n 'xaxis.range': [xMid - xHalf, xMid + xHalf],\n 'yaxis.range': [yMid - yHalf, yMid + yHalf],\n }).catch(() => {});\n }\n }\n\n #autoscale() {\n for (const div of this._chartDivs) {\n if (!div._fullLayout) continue;\n window.Plotly.relayout(div, {\n 'xaxis.autorange': true,\n 'yaxis.autorange': true,\n }).catch(() => {});\n }\n }\n\n #setupResizeObserver() {\n if (!this._plotContent) return;\n this._resizeObserver = createRafResizeObserver(() => {\n if (this._activeTab === 'plot' && this._chartCreated && window.Plotly) {\n for (const div of this._chartDivs) {\n if (div._fullLayout) {\n Plotly.Plots.resize(div).catch(() => {});\n }\n }\n }\n });\n this._resizeObserver.observe(this._plotContent);\n }\n\n #switchTab(tabName) {\n this._activeTab = tabName;\n\n this._plotTab.classList.toggle('active', tabName === 'plot');\n this._dataTab.classList.toggle('active', tabName === 'data');\n this._configTab?.classList.toggle('active', tabName === 'config');\n\n if (this._toolbarActions) {\n this._toolbarActions.style.display = tabName === 'plot' ? '' : 'none';\n }\n\n this._plotContent.style.display = tabName === 'plot' ? 'flex' : 'none';\n this._dataContent.style.display = tabName === 'data' ? 'flex' : 'none';\n if (this._configContent) {\n this._configContent.style.display = tabName === 'config' ? 'flex' : 'none';\n }\n\n if (tabName === 'plot' && this._chartCreated && window.Plotly) {\n for (const div of this._chartDivs) {\n if (div._fullLayout) {\n Plotly.Plots.resize(div).catch(() => {});\n }\n }\n }\n\n if (tabName === 'data') {\n this.#renderDataTable();\n }\n }\n\n // \u2500\u2500 Series visibility toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toggleSeriesPanel() {\n if (this._seriesTogglePanelVisible) {\n this.#hideSeriesPanel();\n } else {\n this.#showSeriesPanel();\n }\n }\n\n #showSeriesPanel() {\n if (!this._seriesTogglePanel || !this._seriesToggleBtn) return;\n\n const btnRect = this._seriesToggleBtn.getBoundingClientRect();\n const containerRect = this._contentEl.getBoundingClientRect();\n\n this._seriesTogglePanel.style.top = `${btnRect.bottom - containerRect.top + 4}px`;\n this._seriesTogglePanel.style.right = `${containerRect.right - btnRect.right}px`;\n this._seriesTogglePanel.style.display = '';\n this._seriesTogglePanelVisible = true;\n\n this._seriesToggleBtn.classList.add('twm-is-active');\n this.#rebuildSeriesToggleList();\n\n this._outsideClickHandler = (e) => {\n if (!this._seriesTogglePanel.contains(e.target) &&\n !this._seriesToggleBtn.contains(e.target)) {\n this.#hideSeriesPanel();\n }\n };\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', this._outsideClickHandler, true);\n });\n }\n\n #hideSeriesPanel() {\n if (this._seriesTogglePanel) {\n this._seriesTogglePanel.style.display = 'none';\n }\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._seriesToggleBtn?.classList.remove('twm-is-active');\n\n if (this._outsideClickHandler) {\n document.removeEventListener('pointerdown', this._outsideClickHandler, true);\n this._outsideClickHandler = null;\n }\n }\n\n #rebuildSeriesToggleList() {\n const panel = this._seriesTogglePanel;\n if (!panel) return;\n panel.innerHTML = '';\n\n // Header with \"All\" / \"None\" actions\n const header = document.createElement('div');\n header.className = 'twm-plot-series-toggle-panel__header';\n\n const title = document.createElement('span');\n title.className = 'twm-plot-series-toggle-panel__title';\n title.textContent = 'Series';\n header.appendChild(title);\n\n const headerActions = document.createElement('div');\n headerActions.className = 'twm-plot-series-toggle-panel__header-actions';\n\n const showAllBtn = document.createElement('button');\n showAllBtn.className = 'twm-plot-series-toggle-panel__action';\n showAllBtn.type = 'button';\n showAllBtn.textContent = 'All';\n showAllBtn.addEventListener('click', () => {\n this._hiddenSeries.clear();\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n const hideAllBtn = document.createElement('button');\n hideAllBtn.className = 'twm-plot-series-toggle-panel__action';\n hideAllBtn.type = 'button';\n hideAllBtn.textContent = 'None';\n hideAllBtn.addEventListener('click', () => {\n for (const label of this._allSeriesLabels) {\n this._hiddenSeries.add(label);\n }\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n headerActions.appendChild(showAllBtn);\n headerActions.appendChild(hideAllBtn);\n header.appendChild(headerActions);\n panel.appendChild(header);\n\n // Split series into model vs overlay\n const modelSeries = this._allSeriesInfo.filter(s => !s.isOverlay);\n const overlaySeries = this._allSeriesInfo.filter(s => s.isOverlay);\n\n const buildItem = ({ label, color, lineStyle }) => {\n const item = document.createElement('label');\n item.className = 'twm-plot-series-toggle-panel__item';\n\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.checked = !this._hiddenSeries.has(label);\n cb.addEventListener('change', () => {\n if (cb.checked) this._hiddenSeries.delete(label);\n else this._hiddenSeries.add(label);\n this.#scheduleRender();\n });\n\n const dashMap = { solid: '', dashed: '4,2', dotted: '1,2' };\n const indicator = document.createElement('div');\n indicator.className = 'twm-plot-series-toggle-panel__line-indicator';\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 28 14');\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', '3');\n line.setAttribute('y1', '7');\n line.setAttribute('x2', '25');\n line.setAttribute('y2', '7');\n line.setAttribute('stroke', color || '#888');\n line.setAttribute('stroke-width', '2');\n line.setAttribute('stroke-linecap', 'round');\n const dash = dashMap[lineStyle] || '';\n if (dash) line.setAttribute('stroke-dasharray', dash);\n svg.appendChild(line);\n indicator.appendChild(svg);\n\n const text = document.createElement('span');\n text.className = 'twm-plot-series-toggle-panel__label';\n text.textContent = label;\n text.title = label;\n\n item.appendChild(cb);\n item.appendChild(indicator);\n item.appendChild(text);\n return item;\n };\n\n // Model series section\n const list = document.createElement('div');\n list.className = 'twm-plot-series-toggle-panel__list';\n\n const subplotGroups = new Map();\n for (const info of modelSeries) {\n if (!subplotGroups.has(info.subplotIndex)) {\n subplotGroups.set(info.subplotIndex, []);\n }\n subplotGroups.get(info.subplotIndex).push(info);\n }\n\n const multipleSubplots = subplotGroups.size > 1;\n\n for (const [spIdx, seriesList] of subplotGroups) {\n if (multipleSubplots) {\n const spName = seriesList[0]?.subplotName || `Subplot ${spIdx + 1}`;\n const spHeader = document.createElement('div');\n spHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n spHeader.textContent = spName;\n list.appendChild(spHeader);\n }\n\n for (const info of seriesList) {\n list.appendChild(buildItem(info));\n }\n }\n\n panel.appendChild(list);\n\n // Overlays section (only if any exist)\n if (overlaySeries.length > 0) {\n const ovList = document.createElement('div');\n ovList.className = 'twm-plot-series-toggle-panel__list';\n\n const ovHeader = document.createElement('div');\n ovHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n ovHeader.textContent = 'Overlays';\n ovList.appendChild(ovHeader);\n\n for (const info of overlaySeries) {\n ovList.appendChild(buildItem(info));\n }\n\n panel.appendChild(ovList);\n }\n }\n\n // \u2500\u2500 Event subscriptions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #subscribeEvents() {\n const { eventBus } = this._services;\n if (!eventBus) return;\n\n this._eventDisposers.push(\n eventBus.on('streaming:delta', () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n this._eventDisposers.push(\n eventBus.on('streaming:complete', () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n // Final analytics arrive asynchronously after streaming:complete\n // (backend fetch + transform). Without this, the popout window may\n // render stale data from a previous run when the dashboard tab\n // didn't receive streaming deltas (e.g. user was on another tab).\n this._eventDisposers.push(\n eventBus.on(this.refreshEvent, () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n }\n\n #toggleLiveUpdate() {\n this._liveUpdate = !this._liveUpdate;\n if (this._liveBtn) {\n this._liveBtn.classList.toggle('twm-is-active', this._liveUpdate);\n const icon = this._liveBtn.querySelector('.material-symbols-outlined');\n if (icon) icon.textContent = this._liveUpdate ? 'stream' : 'lock';\n this._liveBtn.title = this._liveUpdate\n ? 'Live update \u2014 click to lock'\n : 'Locked \u2014 click for live update';\n }\n // If switching back to live, immediately render latest data\n if (this._liveUpdate) this.#scheduleRender();\n }\n\n #scheduleRender() {\n if (this._renderPending) return;\n this._renderPending = true;\n requestAnimationFrame(() => {\n this._renderPending = false;\n this.#render();\n });\n }\n\n // \u2500\u2500 Rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #render() {\n if (!this._window?.isVisible) return;\n\n const results = this._getResults?.();\n if (!results) return;\n\n this._lastResults = results;\n\n // Build series info for toggle panel\n this.#collectSeriesInfo();\n\n // Render all subplot charts\n this.#renderAllCharts(results);\n\n // Update table data\n this.#updateTableData(results);\n\n if (this._activeTab === 'data') {\n this.#renderDataTable();\n }\n }\n\n #collectSeriesInfo() {\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n\n const subplots = this._plotConfig.subplots ?? [];\n for (let spIdx = 0; spIdx < subplots.length; spIdx++) {\n const sp = subplots[spIdx];\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n const label = s.label || s.variable || 'Series';\n this._allSeriesInfo.push({\n label,\n color: s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.lineStyle || 'solid',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n });\n this._allSeriesLabels.push(label);\n\n // Include overlay in toggle list\n if (s.overlay?.etlKey) {\n const ovLabel = s.overlay.label || `${label} (actual)`;\n this._allSeriesInfo.push({\n label: ovLabel,\n color: s.overlay.color || s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.overlay.lineStyle || 'dashed',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n isOverlay: true,\n });\n this._allSeriesLabels.push(ovLabel);\n }\n }\n }\n }\n\n // Prune hidden labels that no longer exist\n for (const label of this._hiddenSeries) {\n if (!this._allSeriesLabels.includes(label)) {\n this._hiddenSeries.delete(label);\n }\n }\n\n // Update toggle panel if visible\n if (this._seriesTogglePanelVisible) {\n const newSig = this._allSeriesInfo.map(s => `${s.subplotIndex}|${s.label}|${s.lineStyle}`).join('\\x00');\n if (newSig !== this._lastTogglePanelSignature) {\n this._lastTogglePanelSignature = newSig;\n this.#rebuildSeriesToggleList();\n }\n }\n\n // Update toggle button icon\n if (this._seriesToggleBtn) {\n const icon = this._seriesToggleBtn.querySelector('.material-symbols-outlined');\n if (icon) {\n icon.textContent = this._hiddenSeries.size > 0 ? 'visibility_off' : 'visibility';\n }\n }\n }\n\n #renderAllCharts(results) {\n if (!window.Plotly) return;\n\n const subplots = this._plotConfig.subplots ?? [];\n for (let i = 0; i < this._chartDivs.length; i++) {\n const chartDiv = this._chartDivs[i];\n const sp = subplots[i];\n if (!chartDiv) continue;\n if (!sp) {\n chartDiv.innerHTML = '<div class=\"twm-plot-no-data\" style=\"color:rgba(255,255,255,0.3);text-align:center;padding:16px;\">No subplot configured.</div>';\n continue;\n }\n this.#renderSubplotChart(chartDiv, sp, results);\n }\n }\n\n async #renderSubplotChart(chartDiv, sp, results) {\n const { time, series } = results;\n const traces = [];\n const layoutAxes = {};\n const yRefByAxisId = {};\n let axisCount = 0;\n\n for (const axis of sp.yAxes ?? []) {\n axisCount++;\n const yAxisKey = axisCount === 1 ? 'yaxis' : `yaxis${axisCount}`;\n const yRef = axisCount === 1 ? 'y' : `y${axisCount}`;\n if (axis.id) yRefByAxisId[axis.id] = yRef;\n\n layoutAxes[yAxisKey] = buildYAxisLayout({\n axisId: yAxisKey,\n title: axis.label || '',\n position: axis.position || 'left',\n scaleType: axis.scale || 'linear',\n min: axis.min,\n max: axis.max,\n showGrid: (sp.yAxes ?? []).length === 1,\n axisPosition: axisCount > 1 ? (axis.position === 'right' ? 1 : 0) : null,\n });\n\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n\n const label = s.label || s.variable;\n\n // Skip hidden series\n if (this._hiddenSeries.has(label)) continue;\n\n // Resolve variable: try result key (paper multi-scenario), exact, then bare (without namespace prefix)\n let rawY = series?.[s._resultKey ?? s.variable];\n if (!rawY && s._resultKey) {\n rawY = series?.[s.variable];\n }\n if (!rawY) {\n const dotIdx = s.variable.indexOf('.');\n if (dotIdx >= 0) rawY = series?.[s.variable.slice(dotIdx + 1)];\n }\n if (!rawY) continue;\n\n const y = Array.isArray(rawY) ? applyNanHandling(rawY, sp.nanHandling ?? 'gap', time) : rawY;\n const seriesTime = s._resultTime ?? time;\n traces.push(buildTrace({\n chartType: sp.chartType || 'line',\n x: seriesTime,\n y,\n name: label,\n color: s.color,\n lineWidth: s.lineWidth ?? 2,\n lineStyle: s.lineStyle ?? 'solid',\n interpolation: sp.interpolation ?? 'linear',\n yAxisId: yRef,\n showMarkers: sp.showDataPoints ?? false,\n stackGroup: s.stackGroup ?? null,\n }));\n\n // Per-series overlay trace (ETL actuals)\n if (s.overlay?.etlKey && this._actuals?.[s.id]) {\n const ovLabel = s.overlay.label || `${label} (actual)`;\n if (!this._hiddenSeries.has(ovLabel)) {\n const act = this._actuals[s.id];\n if (act?.years?.length) {\n const ov = s.overlay;\n const dashMap = { dashed: 'dash', dotted: 'dot', solid: 'solid' };\n traces.push({\n type: 'scatter',\n mode: ov.mode || 'markers+lines',\n x: act.years,\n y: act.values,\n name: ov.label || `${label} (actual)`,\n yaxis: yRef === 'y' ? undefined : yRef,\n line: {\n color: ov.color || s.color,\n width: ov.lineWidth ?? 2,\n dash: dashMap[ov.lineStyle] || 'dash',\n },\n marker: {\n color: ov.color || s.color,\n size: 4,\n symbol: 'circle',\n },\n showlegend: true,\n });\n }\n }\n }\n }\n }\n\n // HP filter traces\n if ((sp.showHpTrend || sp.showHpCycle) && window.pywebview?.api?.hp_filter) {\n const hpLambda = sp.hpLambda ?? 1600;\n for (const trace of [...traces]) {\n if (trace.type && trace.type !== 'scatter' && trace.type !== 'scattergl') continue;\n try {\n const hpResult = await window.pywebview.api.hp_filter({\n data: trace.y,\n lambda: hpLambda,\n });\n if (!hpResult?.ok) continue;\n const { trend, cycle } = hpResult;\n const origColor = trace.line?.color || trace.marker?.color || getSeriesColor(0);\n if (sp.showHpTrend && trend) {\n traces.push({\n x: trace.x, y: trend, type: 'scatter', mode: 'lines',\n name: `${trace.name} (HP Trend)`,\n yaxis: trace.yaxis || 'y',\n line: { color: origColor, width: 2, dash: 'dash' },\n showlegend: true,\n });\n }\n if (sp.showHpCycle && cycle) {\n traces.push({\n x: trace.x, y: cycle, type: 'scatter', mode: 'lines',\n name: `${trace.name} (HP Cycle)`,\n yaxis: trace.yaxis || 'y',\n line: { color: origColor, width: 1, dash: 'dot' },\n showlegend: true,\n });\n }\n } catch (_) { /* ignore HP filter failures */ }\n }\n }\n\n if (traces.length === 0 && this._hiddenSeries.size === 0) {\n chartDiv.innerHTML = `<div class=\"twm-plot-no-data\" style=\"color:rgba(255,255,255,0.3);text-align:center;padding:16px;font-size:11px;\">${this.emptyMessage}</div>`;\n return;\n }\n\n // Popout windows have space \u2014 always show legend\n const legendPos = sp.legendPosition === 'hidden' ? 'top' : (sp.legendPosition ?? 'top');\n const legend = buildLegendLayout(legendPos);\n\n // Clip the x-axis to the data's time range so overlays don't run past t0\u2013t1\n const xRange = time?.length >= 2 ? [time[0], time[time.length - 1]] : undefined;\n\n const { shapes, annotations } = buildOverlayShapes({\n referenceLines: sp.referenceLines,\n shadedBands: sp.shadedBands,\n yRefByAxisId,\n });\n\n const layout = {\n ...layoutAxes,\n ...(shapes.length ? { shapes } : {}),\n ...(annotations.length ? { annotations } : {}),\n xaxis: {\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n automargin: true,\n ...(xRange ? { range: xRange } : {}),\n },\n ...legend,\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc', size: 11 },\n margin: { t: 10, r: 20, b: 40, l: 50 },\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc' },\n },\n autosize: true,\n hovermode: 'x unified',\n };\n\n // Guard: skip if div is detached or zero-size\n if (!chartDiv.isConnected || chartDiv.offsetWidth === 0) return;\n\n try {\n await Plotly.react(chartDiv, traces, layout, { responsive: true, displayModeBar: false });\n this._chartCreated = true;\n } catch (_) {\n // Plotly can throw if div is removed mid-render\n }\n }\n\n // \u2500\u2500 Data table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #updateTableData(results) {\n if (!results) {\n this._tableHeaders = [];\n this._tableRows = [];\n return;\n }\n\n const headers = ['Time'];\n const seriesColumns = [];\n const { time, series } = results;\n const subplots = this._plotConfig.subplots ?? [];\n\n for (const sp of subplots) {\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n const label = s.label || s.variable;\n let rawY = series?.[s._resultKey ?? s.variable];\n if (!rawY && s._resultKey) {\n rawY = series?.[s.variable];\n }\n if (!rawY) {\n const dotIdx = s.variable.indexOf('.');\n if (dotIdx >= 0) rawY = series?.[s.variable.slice(dotIdx + 1)];\n }\n if (!rawY) continue;\n headers.push(label);\n seriesColumns.push(rawY);\n }\n }\n }\n\n const rows = [];\n for (let i = 0; i < time.length; i++) {\n const row = [time[i]];\n for (const col of seriesColumns) {\n row.push(Array.isArray(col) ? col[i] : null);\n }\n rows.push(row);\n }\n\n this._tableHeaders = headers;\n this._tableRows = rows;\n }\n\n #renderDataTable() {\n if (!this._dataTableContainer) return;\n\n if (!this._dataTable) {\n this._dataTable = new DataTable(this._dataTableContainer, {\n headers: this._tableHeaders,\n rows: this._tableRows,\n pageSize: 100,\n pagination: true,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: false,\n emptyMessage: this.tableEmptyMessage,\n services: this._services,\n host: this._host,\n });\n this._dataTable.render();\n } else {\n this._dataTable.setData({\n headers: this._tableHeaders,\n rows: this._tableRows,\n });\n }\n }\n\n // \u2500\u2500 Downloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #downloadCSV() {\n if (this._tableRows.length === 0) {\n this.#notify('Download', 'No data available to download.', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n\n const lines = [this._tableHeaders.join(',')];\n for (const row of this._tableRows) {\n lines.push(row.map(val => this.#csvEscape(val)).join(','));\n }\n const csv = lines.join('\\n');\n\n // null <=> the host has no save dialog behind its `dialogs` capability\n // (host.js). Fall back; do not report it as a failed save.\n const dialogs = this._host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[PlotPopoutWindow] CSV download failed:', err);\n this.#notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Saved ${this._tableRows.length} rows to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save file', 'error');\n }\n return;\n }\n\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n this.#notify('Download', 'Download started', 'info');\n }\n\n #csvEscape(value) {\n if (value == null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n }\n\n async #downloadPNG() {\n // For multi-subplot, capture the grid container as a whole\n // Fall back to first chart div if only one subplot\n const targetDiv = this._chartDivs.length === 1 ? this._chartDivs[0] : this._chartDivs[0];\n if (!targetDiv || !window.Plotly || !this._chartCreated) {\n this.#notify('Download', 'Plot not ready', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}.png`;\n\n try {\n const pngDataUrl = await window.Plotly.toImage(targetDiv, {\n format: 'png',\n width: 1920,\n height: 1080,\n scale: 2,\n });\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = this._host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: pngDataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Plot saved to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save image', 'error');\n }\n } else {\n const link = document.createElement('a');\n link.href = pngDataUrl;\n link.download = filename;\n link.click();\n this.#notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n this._services.logger?.warn?.('[PlotPopoutWindow] PNG download failed', err);\n this.#notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n // \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #notify(title, message, severity = 'info') {\n this._services.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n\n // \u2500\u2500 Cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #dispose() {\n if (this._dataTable) {\n this._dataTable.dispose();\n this._dataTable = null;\n }\n\n this.#hideSeriesPanel();\n\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n this._resizeObserver = null;\n }\n\n for (const disposer of this._eventDisposers) {\n try { disposer?.dispose?.(); } catch (_) {}\n }\n this._eventDisposers = [];\n\n for (const div of this._chartDivs) {\n if (div && window.Plotly) {\n try { purge(div); } catch (_) {}\n }\n }\n\n this._window = null;\n this._contentEl = null;\n this._gridEl = null;\n this._chartDivs = [];\n this._plotTab = null;\n this._dataTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._dataTableContainer = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._lastTogglePanelSignature = null;\n this._hiddenSeries = null;\n this._allSeriesInfo = null;\n this._allSeriesLabels = null;\n this._chartCreated = false;\n this._lastResults = null;\n }\n}\n\n// \u2500\u2500 Singleton window manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst _openWindows = new Map();\n\n/**\n * Open or focus a plot popout window.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.actuals] - ETL overlay data\n * @returns {PlotPopoutWindow}\n */\nexport async function openPlotPopoutWindow(options) {\n const { id } = options;\n let win = _openWindows.get(id);\n if (win?.isVisible) {\n win.bringToFront();\n return win;\n }\n\n // Forward the WHOLE options object. This used to destructure a fixed list of\n // eight names and rebuild the object from them, which means every option added\n // to the constructor from now on would be silently dropped on its way through\n // the factory \u2014 including `refreshEvent`, whose loss would show up as a plot\n // window that simply stops updating, with no error anywhere.\n win = new PlotPopoutWindow({\n ...options,\n onClose: () => _openWindows.delete(id),\n });\n _openWindows.set(id, win);\n\n await win.show();\n return win;\n}\n\n// \u2500\u2500 Raw-traces window (for dashboard tile expand) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Open a ManagedWindow with pre-built Plotly traces.\n *\n * Reuses the same toolbar, tab layout, and download logic as PlotPopoutWindow\n * but accepts ready-made `{ traces, layout }` instead of plotConfig + getResults.\n * Used by dashboard tile widgets whose getExpandData() returns raw Plotly specs.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Array} options.traces - Plotly trace objects\n * @param {Object} options.layout - Plotly layout object\n * @param {Array} [options.tableHeaders] - Column headers for Data tab\n * @param {Array} [options.tableRows] - Row data for Data tab\n * @param {Object} [options.services] - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js); backs Export PNG/CSV.\n * @returns {{ close: Function, bringToFront: Function }}\n */\nexport async function openRawTracesWindow({ id, title, traces, layout, frames, tableHeaders, tableRows, services, host }) {\n const existing = _openWindows.get(id);\n if (existing?.isVisible) {\n existing.bringToFront();\n return existing;\n }\n\n await ensurePlotly();\n\n // State\n let chartDiv = null;\n let chartCreated = false;\n let resizeObserver = null;\n let dataTable = null;\n let managedWindow = null;\n\n // \u2500\u2500 Build content DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n const plotTab = document.createElement('button');\n plotTab.className = 'twm-code-tab active';\n plotTab.type = 'button';\n plotTab.textContent = 'Plot';\n\n const dataTab = document.createElement('button');\n dataTab.className = 'twm-code-tab';\n dataTab.type = 'button';\n dataTab.textContent = 'Data';\n\n tabs.appendChild(plotTab);\n tabs.appendChild(dataTab);\n\n // Toolbar (same layout as PlotPopoutWindow)\n const toolbar = document.createElement('div');\n toolbar.className = 'twm-plot-window-toolbar';\n\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n toolbar.appendChild(spacer);\n\n const actionsGroup = document.createElement('div');\n actionsGroup.className = 'twm-plot-window-toolbar__group';\n\n const mkBtn = (icon, tooltip, onClick) => {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n };\n\n actionsGroup.appendChild(mkBtn('image', 'Download plot as PNG', downloadPNG));\n actionsGroup.appendChild(mkBtn('download', 'Download data as CSV', downloadCSV));\n toolbar.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(toolbar);\n\n // Tab content\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n const plotContent = document.createElement('div');\n plotContent.className = 'twm-plot-tab-content active';\n plotContent.setAttribute('data-tab', 'plot');\n plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n chartDiv = document.createElement('div');\n chartDiv.className = 'twm-plot-window-chart';\n plotContent.appendChild(chartDiv);\n\n const dataContent = document.createElement('div');\n dataContent.className = 'twm-plot-tab-content';\n dataContent.setAttribute('data-tab', 'data');\n dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n const dataTableContainer = document.createElement('div');\n dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n dataContent.appendChild(dataTableContainer);\n\n content.appendChild(plotContent);\n content.appendChild(dataContent);\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n\n // Tab switching\n plotTab.addEventListener('click', () => {\n plotTab.classList.add('active');\n dataTab.classList.remove('active');\n toolbar.style.display = '';\n plotContent.style.display = 'flex';\n dataContent.style.display = 'none';\n if (chartCreated && window.Plotly && chartDiv) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n\n dataTab.addEventListener('click', () => {\n dataTab.classList.add('active');\n plotTab.classList.remove('active');\n toolbar.style.display = 'none';\n plotContent.style.display = 'none';\n dataContent.style.display = 'flex';\n if (!dataTable && tableHeaders?.length) {\n dataTable = new DataTable(dataTableContainer, {\n headers: tableHeaders,\n rows: tableRows || [],\n pagination: true,\n pageSize: 100,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: true,\n emptyMessage: 'No data available',\n services,\n host,\n });\n dataTable.render();\n }\n });\n\n // \u2500\u2500 Create window \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function dispose() {\n if (resizeObserver) { resizeObserver.disconnect(); resizeObserver = null; }\n if (dataTable) { dataTable.dispose(); dataTable = null; }\n if (chartDiv && window.Plotly) { try { purge(chartDiv); } catch (_) {} }\n chartDiv = null;\n chartCreated = false;\n managedWindow = null;\n _openWindows.delete(id);\n }\n\n managedWindow = new ManagedWindow({\n id: `raw-plot-${id}`,\n title: title || 'Chart',\n icon: 'monitoring',\n content: container,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: dispose,\n });\n\n const handle = {\n get isVisible() { return managedWindow?.isVisible ?? false; },\n bringToFront() { managedWindow?.bringToFront?.(); },\n close() { managedWindow?.close?.(); },\n };\n\n _openWindows.set(id, handle);\n managedWindow.show();\n\n // Render plot\n const defaultMargin = { l: 60, r: 30, t: 40, b: 60 };\n const plotLayout = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc', size: 11 },\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc' },\n },\n autosize: true,\n hovermode: 'x unified',\n ...layout,\n margin: { ...defaultMargin, ...(layout?.margin || {}) },\n };\n\n await window.Plotly.newPlot(chartDiv, traces, plotLayout, {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: ['lasso2d', 'select2d', 'toImage'],\n });\n if (Array.isArray(frames) && frames.length) {\n try { await window.Plotly.addFrames(chartDiv, frames); }\n catch (err) { console.warn('[openRawTracesWindow] addFrames failed:', err); }\n }\n chartCreated = true;\n\n // Resize observer\n resizeObserver = createRafResizeObserver(() => {\n if (chartDiv && chartCreated && window.Plotly) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n resizeObserver.observe(plotContent);\n\n // \u2500\u2500 Download helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function notify(ntitle, message, severity = 'info') {\n services?.eventBus?.emit?.('toast:show', { title: ntitle, message, type: severity });\n }\n\n async function downloadPNG() {\n if (!chartDiv || !chartCreated || !window.Plotly) {\n notify('Download', 'Plot not ready', 'warn');\n return;\n }\n const filename = `${(title || 'chart').replace(/[^a-z0-9]/gi, '_')}.png`;\n try {\n const dataUrl = await window.Plotly.toImage(chartDiv, {\n format: 'png', width: 1920, height: 1080, scale: 2,\n });\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: dataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) notify('Download', `Plot saved to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save image', 'error');\n } else {\n const link = document.createElement('a');\n link.href = dataUrl;\n link.download = filename;\n link.click();\n notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n console.error('[openRawTracesWindow] PNG download failed:', err);\n notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n async function downloadCSV() {\n if (!tableRows?.length) {\n notify('Download', 'No data available to download', 'warn');\n return;\n }\n const filename = `${(title || 'data').replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n const csvEscape = (val) => {\n if (val == null) return '';\n const str = String(val);\n return (str.includes(',') || str.includes('\"') || str.includes('\\n'))\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n };\n const lines = [(tableHeaders || []).join(',')];\n for (const row of tableRows) lines.push(row.map(csvEscape).join(','));\n const csv = lines.join('\\n');\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[openRawTracesWindow] CSV download failed:', err);\n notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) notify('Download', `Saved ${tableRows.length} rows to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save file', 'error');\n } else {\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n notify('Download', 'Download started', 'info');\n }\n }\n\n return handle;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Plotly"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/help/help_registry.js", "../src/help/help_modal.js", "../src/ui/components/context_menu.js", "../src/ui/components/modal.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Where the help modal gets its help.\n *\n * HelpModal used to `import { getHelpService, HELP_TOPICS } from './help_service.js'` \u2014\n * and help_service.js is 249 domain words of EcoAgent prose about sectors,\n * currencies, agents and markets. That import was the last framework -> domain\n * edge in the core: a generic modal reaching into one application's manual.\n *\n * The modal now asks this registry, and the application fills it. If nobody\n * fills it, the modal opens and says there is no help \u2014 which is the correct\n * behaviour for a library that ships no documentation about your app.\n *\n * @typedef {Object} HelpProvider\n * @property {() => string[]} getCategories\n * @property {(category: string) => Array<{id: string, title: string}>} getTopicsByCategory\n * @property {(id: string) => Promise<Object|null>} loadTopic\n * @property {(query: string) => Array<Object>} searchTopics\n *\n * @typedef {Object.<string, {label: string, icon: string}>} HelpCategories\n * Keyed by category id; ITERATION ORDER IS DISPLAY ORDER.\n *\n * @typedef {{title: string, welcome: string}} HelpCopy\n * The landing heading. The modal used to hardcode \"EcoAgent Help\" and\n * \"Welcome to EcoAgent!\".\n */\n\n/** A provider with nothing in it. Not an error \u2014 just an app with no help. */\nconst EMPTY_PROVIDER = Object.freeze({\n getCategories: () => [],\n getTopicsByCategory: () => [],\n loadTopic: async () => null,\n searchTopics: () => [],\n});\n\nconst DEFAULT_COPY = Object.freeze({\n title: 'Help',\n welcome: 'Select a topic from the sidebar or browse the categories below.',\n});\n\nlet _provider = EMPTY_PROVIDER;\nlet _categories = Object.freeze({});\nlet _copy = DEFAULT_COPY;\n\n/**\n * @param {HelpProvider} provider\n * @param {HelpCategories} [categories] Display labels + icons, in display order.\n * @param {Partial<HelpCopy>} [copy] Landing heading and welcome line.\n */\nexport function setHelpProvider(provider, categories = {}, copy = {}) {\n _provider = provider ?? EMPTY_PROVIDER;\n _categories = Object.freeze({ ...categories });\n _copy = Object.freeze({ ...DEFAULT_COPY, ...copy });\n}\n\nexport function helpProvider() {\n return _provider;\n}\n\nexport function helpCategories() {\n return _categories;\n}\n\nexport function helpCopy() {\n return _copy;\n}\n", "/**\n * HelpModal - Modal dialog for displaying help content\n *\n * Features:\n * - Markdown rendering with syntax highlighting\n * - Table of contents navigation\n * - Topic search\n * - Category browsing\n * - Keyboard navigation (Escape to close)\n */\n\nimport { helpProvider, helpCategories, helpCopy } from './help_registry.js';\n\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// HelpModal Class\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nlet _activeModal = null;\n\nexport class HelpModal {\n /** The application's help, resolved at use time. */\n get _service() { return helpProvider(); }\n\n get _categories() { return helpCategories(); }\n\n get _copy() { return helpCopy(); }\n\n constructor() {\n // Read LAZILY, not here. A HelpModal can be constructed at boot (the\n // command palette holds one) before the application has registered its\n // help, and a constructor read would freeze the empty default forever.\n this._overlay = null;\n this._modal = null;\n this._currentTopic = null;\n this._searchQuery = '';\n this._boundKeyHandler = this._handleKeyDown.bind(this);\n }\n\n /**\n * Open the help modal.\n * @param {string} [topicId] - Initial topic to display\n */\n async open(topicId = null) {\n // Close any existing modal\n if (_activeModal && _activeModal !== this) {\n _activeModal.close();\n }\n _activeModal = this;\n\n this._createModal();\n document.body.appendChild(this._overlay);\n\n // Add keyboard handler\n document.addEventListener('keydown', this._boundKeyHandler);\n\n // Focus search input\n const searchInput = this._modal.querySelector('.help-search-input');\n if (searchInput) {\n setTimeout(() => searchInput.focus(), 100);\n }\n\n // Load initial topic or show index\n if (topicId) {\n await this._loadTopic(topicId);\n } else {\n this._showIndex();\n }\n }\n\n /**\n * Close the help modal.\n */\n close() {\n if (this._overlay) {\n document.removeEventListener('keydown', this._boundKeyHandler);\n this._overlay.remove();\n this._overlay = null;\n this._modal = null;\n }\n if (_activeModal === this) {\n _activeModal = null;\n }\n }\n\n /**\n * Create the modal DOM structure.\n * @private\n */\n _createModal() {\n // Overlay\n this._overlay = document.createElement('div');\n this._overlay.className = 'help-modal-overlay';\n this._overlay.addEventListener('click', (e) => {\n if (e.target === this._overlay) this.close();\n });\n\n // Modal container\n this._modal = document.createElement('div');\n this._modal.className = 'help-modal';\n this._modal.innerHTML = `\n <div class=\"help-modal__header\">\n <div class=\"help-modal__title\">\n <span class=\"material-symbols-outlined\">help</span>\n <span>Help</span>\n </div>\n <button class=\"help-modal__close\" title=\"Close (Esc)\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n <div class=\"help-modal__search\">\n <span class=\"material-symbols-outlined\">search</span>\n <input type=\"text\" class=\"help-search-input\" placeholder=\"Search help topics...\" autocomplete=\"off\">\n </div>\n <div class=\"help-modal__body\">\n <nav class=\"help-modal__sidebar\">\n <div class=\"help-sidebar__categories\"></div>\n </nav>\n <main class=\"help-modal__content\">\n <div class=\"help-content__loading\">Loading...</div>\n </main>\n </div>\n `;\n\n // Event handlers\n const closeBtn = this._modal.querySelector('.help-modal__close');\n closeBtn.addEventListener('click', () => this.close());\n\n const searchInput = this._modal.querySelector('.help-search-input');\n searchInput.addEventListener('input', (e) => this._handleSearch(e.target.value));\n searchInput.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n if (e.target.value) {\n e.target.value = '';\n this._handleSearch('');\n e.stopPropagation();\n }\n }\n });\n\n // Build sidebar\n this._buildSidebar();\n\n this._overlay.appendChild(this._modal);\n }\n\n /**\n * Build the sidebar navigation.\n * @private\n */\n _buildSidebar() {\n const container = this._modal.querySelector('.help-sidebar__categories');\n const categories = this._service.getCategories();\n\n // Sort categories by order\n const categoryOrder = Object.keys(this._categories);\n categories.sort((a, b) => {\n const orderA = categoryOrder.indexOf(a);\n const orderB = categoryOrder.indexOf(b);\n return (orderA === -1 ? 99 : orderA) - (orderB === -1 ? 99 : orderB);\n });\n\n container.innerHTML = categories.map(category => {\n const topics = this._service.getTopicsByCategory(category);\n const label = this._categories[category]?.label || category;\n const icon = this._categories[category]?.icon || 'folder';\n\n return `\n <div class=\"help-category\" data-category=\"${category}\">\n <div class=\"help-category__header\">\n <span class=\"material-symbols-outlined\">${icon}</span>\n <span>${label}</span>\n </div>\n <ul class=\"help-category__topics\">\n ${topics.map(topic => `\n <li class=\"help-topic-item\" data-topic=\"${topic.id}\">\n ${topic.title}\n </li>\n `).join('')}\n </ul>\n </div>\n `;\n }).join('');\n\n // Add click handlers\n container.querySelectorAll('.help-topic-item').forEach(item => {\n item.addEventListener('click', () => {\n this._loadTopic(item.dataset.topic);\n });\n });\n\n container.querySelectorAll('.help-category__header').forEach(header => {\n header.addEventListener('click', () => {\n header.parentElement.classList.toggle('collapsed');\n });\n });\n }\n\n /**\n * Show the help index page.\n * @private\n */\n _showIndex() {\n const content = this._modal.querySelector('.help-modal__content');\n const categories = this._service.getCategories();\n\n const categoryOrder = Object.keys(this._categories);\n categories.sort((a, b) => {\n const orderA = categoryOrder.indexOf(a);\n const orderB = categoryOrder.indexOf(b);\n return (orderA === -1 ? 99 : orderA) - (orderB === -1 ? 99 : orderB);\n });\n\n content.innerHTML = `\n <div class=\"help-index\">\n <h1>${this._copy.title}</h1>\n <p>${this._copy.welcome}</p>\n\n <div class=\"help-index__grid\">\n ${categories.map(category => {\n const topics = this._service.getTopicsByCategory(category);\n const label = this._categories[category]?.label || category;\n const icon = this._categories[category]?.icon || 'folder';\n\n return `\n <div class=\"help-index__category\" data-category=\"${category}\">\n <div class=\"help-index__category-header\">\n <span class=\"material-symbols-outlined\">${icon}</span>\n <span>${label}</span>\n </div>\n <ul class=\"help-index__topics\">\n ${topics.slice(0, 3).map(topic => `\n <li class=\"help-index__topic\" data-topic=\"${topic.id}\">\n ${topic.title}\n </li>\n `).join('')}\n ${topics.length > 3 ? `<li class=\"help-index__more\">+${topics.length - 3} more</li>` : ''}\n </ul>\n </div>\n `;\n }).join('')}\n </div>\n </div>\n `;\n\n // Add click handlers\n content.querySelectorAll('.help-index__topic').forEach(item => {\n item.addEventListener('click', () => {\n this._loadTopic(item.dataset.topic);\n });\n });\n }\n\n /**\n * Load and display a topic.\n * @param {string} topicId - Topic ID\n * @private\n */\n async _loadTopic(topicId) {\n const content = this._modal.querySelector('.help-modal__content');\n content.innerHTML = '<div class=\"help-content__loading\">Loading...</div>';\n\n // Update sidebar selection\n this._modal.querySelectorAll('.help-topic-item').forEach(item => {\n item.classList.toggle('active', item.dataset.topic === topicId);\n });\n\n try {\n const topic = await this._service.loadTopic(topicId);\n this._currentTopic = topicId;\n\n content.innerHTML = `\n <div class=\"help-content__article\">\n <div class=\"help-content__breadcrumb\">\n <a href=\"#\" class=\"help-breadcrumb__home\" title=\"Help Index\">\n <span class=\"material-symbols-outlined\">home</span>\n </a>\n <span class=\"help-breadcrumb__separator\">/</span>\n <span class=\"help-breadcrumb__title\">${topic.title}</span>\n </div>\n <article class=\"help-article\">\n ${topic.html}\n </article>\n </div>\n `;\n\n // Add breadcrumb handler\n content.querySelector('.help-breadcrumb__home').addEventListener('click', (e) => {\n e.preventDefault();\n this._showIndex();\n });\n } catch (error) {\n content.innerHTML = `\n <div class=\"help-content__error\">\n <span class=\"material-symbols-outlined\">error</span>\n <p>Failed to load help topic.</p>\n </div>\n `;\n }\n }\n\n /**\n * Handle search input.\n * @param {string} query - Search query\n * @private\n */\n _handleSearch(query) {\n this._searchQuery = query;\n const content = this._modal.querySelector('.help-modal__content');\n\n if (!query.trim()) {\n this._showIndex();\n return;\n }\n\n const results = this._service.searchTopics(query);\n\n if (results.length === 0) {\n content.innerHTML = `\n <div class=\"help-search-results\">\n <h2>Search Results</h2>\n <p class=\"help-search-empty\">No results found for \"${query}\"</p>\n </div>\n `;\n return;\n }\n\n content.innerHTML = `\n <div class=\"help-search-results\">\n <h2>Search Results</h2>\n <p class=\"help-search-count\">${results.length} result${results.length !== 1 ? 's' : ''} for \"${query}\"</p>\n <ul class=\"help-search-list\">\n ${results.map(topic => `\n <li class=\"help-search-item\" data-topic=\"${topic.id}\">\n <span class=\"help-search-item__title\">${topic.title}</span>\n <span class=\"help-search-item__category\">${this._categories[topic.category]?.label || topic.category}</span>\n </li>\n `).join('')}\n </ul>\n </div>\n `;\n\n // Add click handlers\n content.querySelectorAll('.help-search-item').forEach(item => {\n item.addEventListener('click', () => {\n this._loadTopic(item.dataset.topic);\n });\n });\n }\n\n /**\n * Handle keyboard events.\n * @param {KeyboardEvent} event\n * @private\n */\n _handleKeyDown(event) {\n if (event.key === 'Escape') {\n this.close();\n }\n }\n\n /**\n * Static method to open help modal.\n * @param {string} [topicId] - Initial topic\n * @returns {HelpModal}\n */\n static open(topicId = null) {\n const modal = new HelpModal();\n modal.open(topicId);\n return modal;\n }\n\n /**\n * Get the currently active modal.\n * @returns {HelpModal|null}\n */\n static getActive() {\n return _activeModal;\n }\n}\n\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// Global Help Shortcut\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n/**\n * Open help modal with the `?` key. (F1 is reserved for top-nav Home.)\n */\nfunction setupGlobalHelpShortcut() {\n document.addEventListener('keydown', (event) => {\n if (event.key !== '?') return;\n // Don't hijack `?` typed into a field (search boxes, editors).\n const t = event.target;\n if (t?.closest?.(\n 'input, textarea, select, [contenteditable=\"true\"]')) return;\n event.preventDefault();\n if (_activeModal) {\n _activeModal.close();\n } else {\n HelpModal.open();\n }\n });\n}\n\n// Initialize global shortcut\nif (typeof document !== 'undefined') {\n setupGlobalHelpShortcut();\n}\n\nexport default HelpModal;\n", "/**\n * context_menu.js \u2014 small popup menu that matches Ecosim's `.context-menu`\n * idiom (see main_new.css line 9713 and ui/js/ui/components/data_table.js).\n *\n * Usage:\n * showContextMenu(x, y, [\n * { label: 'Open', icon: 'open_in_new', action: 'open' },\n * { separator: true },\n * { label: 'Delete', icon: 'delete', action: 'delete', danger: true },\n * ], (action) => { ... });\n *\n * The menu auto-closes on outside click / scroll / Escape.\n */\n\nlet _activeMenu = null;\n\nexport function showContextMenu(x, y, items, onAction) {\n hideContextMenu();\n\n const menu = document.createElement('div');\n menu.className = 'twm-context-menu ea-context-menu';\n\n for (const it of items) {\n if (it.separator) {\n const sep = document.createElement('div');\n sep.className = 'twm-context-menu__separator';\n menu.appendChild(sep);\n continue;\n }\n const row = document.createElement('div');\n let cls = 'twm-context-menu-item';\n if (it.danger) cls += ' twm-delete-node';\n if (it.disabled) cls += ' disabled';\n row.className = cls;\n row.innerHTML = `\n <span class=\"material-symbols-outlined\">${it.icon || ''}</span>\n <span>${escapeHtml(it.label)}</span>\n `;\n if (!it.disabled) {\n row.addEventListener('click', (e) => {\n e.stopPropagation();\n hideContextMenu();\n onAction?.(it.action);\n });\n }\n menu.appendChild(row);\n }\n\n document.body.appendChild(menu);\n menu.style.display = 'block';\n _activeMenu = menu;\n\n // Position with viewport clamping.\n const rect = menu.getBoundingClientRect();\n const left = Math.min(x, window.innerWidth - rect.width - 8);\n const top = Math.min(y, window.innerHeight - rect.height - 8);\n menu.style.left = `${Math.max(0, left)}px`;\n menu.style.top = `${Math.max(0, top)}px`;\n\n // Close on outside click / scroll / Escape.\n setTimeout(() => {\n document.addEventListener('mousedown', _outsideHandler, { once: true, capture: true });\n }, 0);\n document.addEventListener('keydown', _escHandler);\n window.addEventListener('scroll', hideContextMenu, { once: true, capture: true });\n}\n\nexport function hideContextMenu() {\n if (!_activeMenu) return;\n _activeMenu.remove();\n _activeMenu = null;\n document.removeEventListener('keydown', _escHandler);\n}\n\nfunction _outsideHandler(e) {\n if (_activeMenu && !_activeMenu.contains(e.target)) hideContextMenu();\n}\n\nfunction _escHandler(e) {\n if (e.key === 'Escape') hideContextMenu();\n}\n\nfunction escapeHtml(s) {\n return String(s).replace(/[&<>\"']/g, (c) => ({\n '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''',\n }[c]));\n}\n", "/**\n * Modal helpers \u2014 prompt with form, yes/no confirm.\n *\n * Built on the canonical `ManagedWindow` (with `modal: true`) so dialogs\n * go through the same window system as everything else: same chrome,\n * same backdrop, same Esc-to-close behaviour, same z-stacking.\n *\n * Returns Promises that resolve with the form data (or null on cancel)\n * / a boolean (confirm).\n *\n * Field schema:\n * { name, label, type='text', default, step?, options?, required?,\n * placeholder?, hint?, validator?, rows?, create? }\n *\n * - type: 'text' | 'number' | 'password' | 'select' | 'textarea' |\n * 'checkbox'\n * - hint: small dim help line rendered under the field\n * - validator: fn(value, allValues) => string | null (inline error)\n * - rows: number of textarea rows (only used for type='textarea')\n *\n * Section dividers \u2014 entries of the form `{ section: 'Label' }` are\n * rendered as a small uppercase heading that groups the fields below\n * them. Useful for longer forms.\n *\n * Dependent-property pick-or-create \u2014 a `select` field that carries a\n * `create` spec renders as a **type-ahead combobox** instead of a\n * dropdown: the user picks an existing option OR types a new value.\n * On submit, a value that isn't an existing option is created via\n * `create.onCreate(value)` before the form resolves:\n *\n * {\n * name: 'asset_kind', label: 'Asset kind', type: 'select',\n * options: [...], // existing values (autocomplete)\n * create: {\n * onCreate: async (typed) => finalValue | null, // make the entity\n * hint: 'new asset kind', // shown when the typed value is new\n * },\n * }\n */\n\nimport { ManagedWindow } from '../../ui/components/managed_window.js';\n\nlet _modalSeq = 1;\n\nexport function openForm({ title, fields = [], defaults = {}, submitLabel = 'OK' } = {}) {\n return new Promise((resolve) => {\n // Build the form body \u2014 same markup as the legacy overlay,\n // minus the outer .ea-modal wrapper (ManagedWindow owns the\n // chrome now).\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n body.innerHTML = `\n <form class=\"twm-modal__form\">\n ${fields.map((f) => _renderEntry(f, defaults[f.name] ?? f.default)).join('')}\n <div class=\"twm-modal__error\" data-role=\"form-error\" hidden></div>\n <div class=\"twm-modal__actions\">\n <button type=\"button\" class=\"twm-btn\" data-action=\"cancel\">Cancel</button>\n <button type=\"submit\" class=\"twm-btn twm-btn--primary\">${submitLabel}</button>\n </div>\n </form>\n `;\n\n const win = new ManagedWindow({\n id: `twm-modal-${_modalSeq++}`,\n title: title || 'Dialog',\n icon: 'edit_note',\n content: body,\n modal: true,\n canMinimize: false,\n canMaximize: false,\n canResize: false,\n canDrag: true,\n defaultWidth: _estimateWidth(fields),\n defaultHeight: _estimateHeight(fields),\n onClose: () => { if (!_resolved) { _resolved = true; resolve(null); } },\n });\n win.show();\n\n let _resolved = false;\n const close = (result) => {\n if (_resolved) return;\n _resolved = true;\n resolve(result);\n try { win.close({ force: true }); } catch {}\n };\n\n const errEl = body.querySelector('[data-role=\"form-error\"]');\n const showError = (msg) => {\n if (!errEl) return;\n errEl.textContent = msg;\n errEl.hidden = !msg;\n };\n body.querySelector('[data-action=\"cancel\"]')?.addEventListener('click', () => close(null));\n\n const formFields = fields.filter((f) => !f.section);\n for (const f of formFields) {\n if (f.type === 'select' && f.create) _wireComboboxHint(body, f);\n }\n\n const clearFieldError = (name) => {\n const row = body.querySelector(`[data-field-row=\"${name}\"]`);\n const errEl = body.querySelector(`[data-field-error=\"${name}\"]`);\n if (row) row.classList.remove('twm-is-invalid');\n if (errEl) { errEl.textContent = ''; errEl.hidden = true; }\n };\n const setFieldError = (name, msg) => {\n const row = body.querySelector(`[data-field-row=\"${name}\"]`);\n const errEl = body.querySelector(`[data-field-error=\"${name}\"]`);\n if (row) row.classList.add('twm-is-invalid');\n if (errEl) { errEl.textContent = msg; errEl.hidden = false; }\n };\n // Clear per-field errors on input so the user sees the row recover.\n for (const f of formFields) {\n const el = body.querySelector(`[name=\"${f.name}\"]`);\n el?.addEventListener('input', () => clearFieldError(f.name));\n el?.addEventListener('change', () => clearFieldError(f.name));\n }\n\n body.querySelector('form').addEventListener('submit', async (e) => {\n e.preventDefault();\n const submitBtn = body.querySelector('button[type=\"submit\"]');\n showError('');\n const data = {};\n for (const f of formFields) {\n const el = body.querySelector(`[name=\"${f.name}\"]`);\n if (!el) continue;\n let v;\n if (f.type === 'checkbox') {\n v = !!el.checked;\n } else if (f.type === 'number') {\n v = (el.value === '' ? null : Number(el.value));\n } else {\n v = el.value;\n }\n if (f.type === 'select' && f.create) {\n const known = new Set(_optionValues(f.options));\n if (v && !known.has(v)) {\n if (submitBtn) submitBtn.disabled = true;\n let created;\n let failMsg = null;\n try { created = await f.create.onCreate(v); }\n catch (err) { created = null; failMsg = err?.message || String(err); }\n if (submitBtn) submitBtn.disabled = false;\n if (created == null) {\n const hint = (f.create && f.create.hint) || f.label.toLowerCase();\n showError(failMsg\n ? `Couldn't create ${hint} \"${v}\": ${failMsg}`\n : `Couldn't create ${hint} \"${v}\". See the toast for details.`);\n return;\n }\n v = created;\n }\n }\n data[f.name] = v;\n }\n // Per-field validators run after collection so they can see\n // peer values (e.g. confirm-password matches password).\n let firstBadName = null;\n for (const f of formFields) {\n clearFieldError(f.name);\n if (typeof f.validator !== 'function') continue;\n let msg = null;\n try { msg = f.validator(data[f.name], data); } catch (err) { msg = err?.message || String(err); }\n if (msg) {\n setFieldError(f.name, msg);\n if (!firstBadName) firstBadName = f.name;\n }\n }\n if (firstBadName) {\n body.querySelector(`[name=\"${firstBadName}\"]`)?.focus();\n return;\n }\n close(data);\n });\n\n // Focus first field on next frame so the managed-window mount\n // settles before we steal focus.\n requestAnimationFrame(() => {\n body.querySelector('input, select, textarea')?.focus();\n });\n });\n}\n\n\nexport function openConfirm({\n title, message, confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n danger = false, icon = null,\n} = {}) {\n return new Promise((resolve) => {\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n const cls = danger ? 'twm-btn twm-btn--danger' : 'twm-btn twm-btn--primary';\n body.innerHTML = `\n <div class=\"twm-modal__body\">${message}</div>\n <div class=\"twm-modal__actions\">\n <button type=\"button\" class=\"twm-btn\" data-action=\"cancel\">${cancelLabel}</button>\n <button type=\"button\" class=\"${cls}\" data-action=\"confirm\">${confirmLabel}</button>\n </div>\n `;\n\n let _resolved = false;\n const win = new ManagedWindow({\n id: `twm-confirm-${_modalSeq++}`,\n title: title || 'Confirm',\n icon: icon || (danger ? 'warning' : 'help'),\n content: body,\n modal: true,\n canMinimize: false,\n canMaximize: false,\n canResize: false,\n canDrag: true,\n defaultWidth: 380,\n defaultHeight: 180,\n onClose: () => { if (!_resolved) { _resolved = true; resolve(false); } },\n });\n win.show();\n const close = (v) => {\n if (_resolved) return;\n _resolved = true;\n resolve(v);\n try { win.close({ force: true }); } catch {}\n };\n body.querySelector('[data-action=\"cancel\"]').addEventListener('click', () => close(false));\n body.querySelector('[data-action=\"confirm\"]').addEventListener('click', () => close(true));\n requestAnimationFrame(() => {\n body.querySelector(`[data-action=\"${danger ? 'cancel' : 'confirm'}\"]`)?.focus();\n });\n });\n}\n\n\n/**\n * `openModal` \u2014 rich-content modal. The third helper alongside\n * `openForm` (field-based) and `openConfirm` (yes/no).\n *\n * Use when the modal body is arbitrary DOM the caller renders itself\n * \u2014 a chart, a Monaco editor, a table, a diff view. The shell still\n * goes through ManagedWindow so the chrome, focus trap, Esc handling,\n * and z-stacking match every other modal in the app.\n *\n * Schema:\n * - `title` window title (string)\n * - `icon` optional material-symbols-outlined glyph for the\n * title bar; defaults to `info`\n * - `content` HTMLElement appended into the body. Caller owns\n * rendering \u2014 `openModal` doesn't size or style the\n * internal content beyond making it scrollable.\n * - `actions` `[{ label, value, primary?, danger? }, \u2026]`. If\n * omitted, defaults to a single `[Close]` action that\n * resolves with `null`. The first action with\n * `primary: true` is the rightmost; otherwise the\n * last action wins. Esc / X / backdrop resolve with\n * `null` regardless of what's in `actions`.\n * - `width`,\n * `height` initial size in px. Defaults: 640 \u00D7 480.\n * - `onMount` optional `(contentEl) => void` invoked once after\n * the content is appended \u2014 handy when the caller\n * needs the bounding rect to size a chart / Monaco /\n * SVG inside the body.\n * - `backdropBlur` backdrop blur radius in px (`0` disables it).\n * - `backdropOpacity` backdrop dim, 0 (clear) \u2026 1 (opaque). Use a low\n * value (with `backdropBlur: 0`) to keep the background\n * legible \u2014 e.g. a live-applied editor where you want to\n * watch the content behind update. Omit both to inherit\n * the default look (blur 2px over a 50% dim).\n *\n * Returns a Promise resolving with the chosen action's `value`, or\n * `null` if the user dismissed the modal.\n */\nexport function openModal({\n title = 'Dialog',\n icon = 'info',\n content = null,\n actions = null,\n width = 640,\n height = 480,\n onMount = null,\n backdropBlur = undefined,\n backdropOpacity = undefined,\n} = {}) {\n return new Promise((resolve) => {\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n\n const bodyInner = document.createElement('div');\n bodyInner.className = 'twm-modal__body twm-modal__body--rich';\n if (content instanceof HTMLElement) bodyInner.appendChild(content);\n body.appendChild(bodyInner);\n\n // Actions row \u2014 default = single Close button. Esc / backdrop /\n // X all bypass this and resolve with null.\n const acts = Array.isArray(actions) && actions.length > 0\n ? actions\n : [{ label: 'Close', value: null }];\n const actionsEl = document.createElement('div');\n actionsEl.className = 'twm-modal__actions';\n acts.forEach((a, i) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n let cls = 'twm-btn';\n if (a.primary) cls += ' twm-btn--primary';\n if (a.danger) cls += ' twm-btn--danger';\n btn.className = cls;\n btn.textContent = String(a.label || '');\n btn.dataset.actionIdx = String(i);\n actionsEl.appendChild(btn);\n });\n body.appendChild(actionsEl);\n\n let _resolved = false;\n const win = new ManagedWindow({\n id: `twm-modal-${_modalSeq++}`,\n title,\n icon,\n content: body,\n modal: true,\n backdropBlur,\n backdropOpacity,\n canMinimize: false,\n canMaximize: false,\n canResize: true,\n canDrag: true,\n defaultWidth: width,\n defaultHeight: height,\n onClose: () => { if (!_resolved) { _resolved = true; resolve(null); } },\n });\n win.show();\n\n const close = (value) => {\n if (_resolved) return;\n _resolved = true;\n resolve(value);\n try { win.close({ force: true }); } catch {}\n };\n actionsEl.addEventListener('click', (e) => {\n const btn = e.target.closest('[data-action-idx]');\n if (!btn) return;\n const idx = Number(btn.dataset.actionIdx);\n const a = acts[idx];\n if (!a) return;\n // `keepOpen` actions are side-effects (Copy, Apply\n // Without Close, etc.): if the action's `onClick` returns\n // anything (or just runs), the modal stays open. Use this\n // for Copy buttons and the like.\n if (a.keepOpen) {\n // `onClick` receives `close` so the handler can\n // validate, do an async side-effect, and only then\n // dismiss the modal with whatever value it chooses.\n // Returning early without calling `close` leaves the\n // modal open (which is the whole point of keepOpen).\n try { a.onClick?.(close); } catch (err) { console.warn(err); }\n return;\n }\n close(a.value);\n });\n\n // onMount runs after the next frame so layout has settled and\n // the inner content has a real bounding box for sizing.\n if (typeof onMount === 'function') {\n requestAnimationFrame(() => {\n try { onMount(bodyInner); } catch (err) { console.warn(err); }\n });\n }\n // Focus the primary button (or the last action) so Enter\n // resolves the most-likely intended outcome.\n requestAnimationFrame(() => {\n const idx = acts.findIndex((a) => a.primary);\n const which = idx >= 0 ? idx : acts.length - 1;\n actionsEl.querySelector(`[data-action-idx=\"${which}\"]`)?.focus();\n });\n });\n}\n\n\n// \u2500\u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction _estimateHeight(fields) {\n // Header (~36) + actions row (~46) + section dividers (~32 each)\n // + per-field rows (~46 text, ~140 textarea, ~32 checkbox)\n // + body padding. Clamped to 200..80vh.\n let body = 0;\n for (const f of fields) {\n if (f.section) body += 32;\n else if (f.type === 'textarea') {\n const rows = Number(f.rows) || 4;\n body += 32 + rows * 18;\n if (f.hint) body += 16;\n }\n else if (f.type === 'checkbox') body += 32;\n else { body += 46; if (f.hint) body += 16; }\n }\n const base = 36 + 46 + 28 + body;\n const max = Math.floor(window.innerHeight * 0.8);\n return Math.max(200, Math.min(base, max));\n}\n\nfunction _estimateWidth(fields) {\n // Forms with a textarea or section divider get the wider layout so\n // multi-line content + grouped fields breathe; otherwise 480 px is\n // enough for label + single-line input pairs.\n const wide = fields.some((f) => f && (f.type === 'textarea' || f.section));\n return wide ? 640 : 480;\n}\n\nfunction _optionValues(options) {\n return (options || []).map((o) => (typeof o === 'object') ? o.value : o);\n}\n\n\n/** Show / hide the \"\u21B3 will create \u2026\" hint as the user types into a\n * create-capable combobox. */\nfunction _wireComboboxHint(host, f) {\n const input = host.querySelector(`input[name=\"${f.name}\"]`);\n const hintEl = host.querySelector(`.twm-combobox__hint[data-for=\"${f.name}\"]`);\n if (!input || !hintEl) return;\n const known = new Set(_optionValues(f.options));\n const label = (f.create && f.create.hint) || 'new entry';\n const update = () => {\n const v = input.value.trim();\n if (v && !known.has(v)) {\n hintEl.textContent = `\u21B3 will create ${label} \u201C${v}\u201D`;\n hintEl.hidden = false;\n } else {\n hintEl.hidden = true;\n }\n };\n input.addEventListener('input', update);\n update();\n}\n\n\nfunction _renderEntry(f, value) {\n if (f && f.section != null) {\n return `<div class=\"twm-modal__section\">${_esc(f.section)}</div>`;\n }\n return _renderField(f, value);\n}\n\nfunction _renderField(f, value) {\n const required = f.required ? 'required' : '';\n const rowMod = (f.type === 'textarea') ? ' twm-modal__row--multiline' : '';\n const hintHtml = f.hint\n ? `<div class=\"twm-modal__hint--field\">${_esc(f.hint)}</div>` : '';\n const errHtml = `<div class=\"twm-modal__field-error\" data-field-error=\"${f.name}\" hidden></div>`;\n const wrap = (inner) => `\n <label class=\"twm-modal__row${rowMod}\" data-field-row=\"${f.name}\">\n <span>${_esc(f.label || '')}</span>\n ${inner}\n ${hintHtml}\n ${errHtml}\n </label>\n `;\n\n if (f.type === 'checkbox') {\n const checked = (value === true || value === 'true') ? 'checked' : '';\n return `\n <label class=\"twm-modal__row\" data-field-row=\"${f.name}\">\n <span></span>\n <span class=\"twm-modal__check\">\n <input name=\"${f.name}\" type=\"checkbox\" ${checked}>\n <span>${_esc(f.label || '')}</span>\n </span>\n ${hintHtml}\n ${errHtml}\n </label>\n `;\n }\n\n if (f.type === 'textarea') {\n const v = value == null ? '' : String(value);\n const rows = f.rows != null ? `rows=\"${Number(f.rows) || 4}\"` : 'rows=\"4\"';\n const placeholder = f.placeholder ? `placeholder=\"${_esc(f.placeholder)}\"` : '';\n return wrap(`<textarea name=\"${f.name}\" ${rows} ${placeholder} ${required}>${_esc(v)}</textarea>`);\n }\n\n const v = value == null ? '' : String(value);\n if (f.type === 'select' && f.create) {\n const dlId = `ea-dl-${f.name}-${_modalSeq}`;\n const opts = _optionValues(f.options)\n .map((ov) => `<option value=\"${_esc(ov)}\"></option>`).join('');\n const placeholder = f.placeholder\n ? `placeholder=\"${_esc(f.placeholder)}\"` : 'placeholder=\"type to pick or create\u2026\"';\n return wrap(`\n <div class=\"twm-combobox\">\n <input name=\"${f.name}\" type=\"text\" list=\"${dlId}\"\n value=\"${_esc(v)}\" ${placeholder} ${required}\n autocomplete=\"off\">\n <datalist id=\"${dlId}\">${opts}</datalist>\n <span class=\"twm-combobox__hint\" data-for=\"${f.name}\" hidden></span>\n </div>\n `);\n }\n if (f.type === 'select') {\n const opts = (f.options || []).map((o) => {\n const ov = (typeof o === 'object') ? o.value : o;\n const ol = (typeof o === 'object') ? o.label : o;\n return `<option value=\"${_esc(ov)}\" ${ov === v ? 'selected' : ''}>${_esc(ol)}</option>`;\n }).join('');\n return wrap(`<select name=\"${f.name}\" ${required}>${opts}</select>`);\n }\n const step = f.step != null ? `step=\"${f.step}\"` : '';\n const placeholder = f.placeholder ? `placeholder=\"${_esc(f.placeholder)}\"` : '';\n const type = (f.type === 'number' || f.type === 'password') ? f.type : 'text';\n return wrap(`<input name=\"${f.name}\" type=\"${type}\" value=\"${_esc(v)}\" ${step} ${placeholder} ${required}>`);\n}\n\nfunction _esc(s) {\n return String(s == null ? '' : s)\n .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["errEl", "v", "placeholder"]
|
|
7
|
-
}
|