flexdesk 0.16.1 → 0.17.1

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.
Files changed (262) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +0 -0
  3. package/README.md +2435 -42
  4. package/THIRD_PARTY_LICENSES.md +0 -0
  5. package/canvas.js +18 -0
  6. package/charts.js +21 -0
  7. package/core.js +14 -0
  8. package/css/base.css +1834 -75
  9. package/css/flexdesk.css +3165 -159
  10. package/css/overrides.css +16 -0
  11. package/css/reset.css +0 -0
  12. package/css/tokens.css +0 -0
  13. package/dist/canvas.js +6 -239
  14. package/dist/canvas.js.map +3 -3
  15. package/dist/charts.js +707 -18
  16. package/dist/charts.js.map +4 -4
  17. package/dist/chunk-3PHCPZHT.js +0 -0
  18. package/dist/chunk-3PHCPZHT.js.map +0 -0
  19. package/dist/chunk-4A7SJC3T.js +503 -0
  20. package/dist/chunk-4A7SJC3T.js.map +7 -0
  21. package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
  22. package/dist/chunk-CVMCZZX2.js.map +7 -0
  23. package/dist/chunk-D3COLZZ2.js +1311 -0
  24. package/dist/chunk-D3COLZZ2.js.map +7 -0
  25. package/dist/chunk-FOOS3T5L.js +0 -0
  26. package/dist/chunk-FOOS3T5L.js.map +0 -0
  27. package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
  28. package/dist/chunk-GOQLR5WR.js.map +7 -0
  29. package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
  30. package/dist/chunk-HNU6MM2B.js.map +7 -0
  31. package/dist/chunk-HYJYYEPK.js +375 -0
  32. package/dist/chunk-HYJYYEPK.js.map +7 -0
  33. package/dist/chunk-JKZLNKG6.js +2041 -0
  34. package/dist/chunk-JKZLNKG6.js.map +7 -0
  35. package/dist/chunk-JYWURG5T.js +0 -0
  36. package/dist/chunk-JYWURG5T.js.map +0 -0
  37. package/dist/{chunk-FBGP5KN5.js → chunk-LWV23YVE.js} +5073 -532
  38. package/dist/chunk-LWV23YVE.js.map +7 -0
  39. package/dist/chunk-N7HC3ADV.js +30 -0
  40. package/dist/chunk-N7HC3ADV.js.map +7 -0
  41. package/dist/{chunk-RQM5Z2MU.js → chunk-RMTRWWEO.js} +633 -311
  42. package/dist/chunk-RMTRWWEO.js.map +7 -0
  43. package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
  44. package/dist/chunk-UURZ37SD.js.map +7 -0
  45. package/dist/{chunk-B5Q53LAJ.js → chunk-UWO43BZU.js} +2 -2
  46. package/dist/chunk-UWO43BZU.js.map +7 -0
  47. package/dist/chunk-WVFGV5FT.js +0 -0
  48. package/dist/chunk-WVFGV5FT.js.map +0 -0
  49. package/dist/core.js +170 -118
  50. package/dist/core.js.map +2 -2
  51. package/dist/editor.js +156 -70
  52. package/dist/editor.js.map +2 -2
  53. package/dist/flexdesk.css +3165 -159
  54. package/dist/flow.js +2789 -306
  55. package/dist/flow.js.map +4 -4
  56. package/dist/host.js +109 -3
  57. package/dist/host.js.map +3 -3
  58. package/dist/reset.css +0 -0
  59. package/dist/tile_registry-6WZPTUZV.js +0 -0
  60. package/dist/tile_registry-6WZPTUZV.js.map +0 -0
  61. package/dist/tiles.js +657 -234
  62. package/dist/tiles.js.map +4 -4
  63. package/dist/tokens.css +0 -0
  64. package/dist/widgets.js +3290 -2124
  65. package/dist/widgets.js.map +4 -4
  66. package/dist/wm.js +1227 -347
  67. package/dist/wm.js.map +4 -4
  68. package/editor.js +20 -0
  69. package/flow.js +21 -0
  70. package/host.js +14 -0
  71. package/package.json +12 -1
  72. package/src/canvas/canvas_adapter.js +5 -0
  73. package/src/canvas/edge_router.js +0 -0
  74. package/src/canvas/graph/connector_router.js +0 -0
  75. package/src/canvas/graph/history_service.js +0 -0
  76. package/src/canvas/graph/node_platform.js +0 -0
  77. package/src/canvas/index.js +1 -0
  78. package/src/canvas/layered_layout.js +244 -0
  79. package/src/charts/chart_types.js +0 -0
  80. package/src/charts/data_series_plot_window.js +0 -0
  81. package/src/charts/downsample.js +2 -2
  82. package/src/charts/plot_config.js +53 -29
  83. package/src/charts/plot_config_editor.js +627 -0
  84. package/src/charts/plot_grid.js +449 -0
  85. package/src/charts/plot_popout_window.js +103 -317
  86. package/src/charts/plotly_wrapper.js +22 -2
  87. package/src/charts/series_transforms.js +206 -0
  88. package/src/core/event_bus.js +0 -0
  89. package/src/core/logging.js +1 -1
  90. package/src/core/settings.js +105 -19
  91. package/src/core/state_guard.js +93 -51
  92. package/src/core/state_guard_config.js +85 -74
  93. package/src/core/state_machine.js +0 -0
  94. package/src/editor/editor_pane.js +3 -3
  95. package/src/editor/monaco_editor_factory.js +124 -60
  96. package/src/editor/monaco_loader.js +103 -28
  97. package/src/editor/notebook_search.js +0 -0
  98. package/src/editor/notebook_tab_bar.js +38 -52
  99. package/src/editor/notebook_undo_manager.js +0 -0
  100. package/src/editor/split_pane_container.js +6 -3
  101. package/src/flow/canvas_editor/connections.js +90 -0
  102. package/src/flow/canvas_editor/editor.js +2351 -153
  103. package/src/flow/canvas_editor/index.js +2 -1
  104. package/src/flow/canvas_editor/layout.js +119 -12
  105. package/src/flow/canvas_editor/strings.js +80 -0
  106. package/src/flow/kit/always_before.js +0 -0
  107. package/src/flow/kit/catalogue.js +97 -3
  108. package/src/flow/kit/chip_input.js +0 -0
  109. package/src/flow/kit/dom.js +0 -0
  110. package/src/flow/kit/findings.js +0 -0
  111. package/src/flow/kit/history.js +0 -0
  112. package/src/flow/kit/index.js +3 -3
  113. package/src/flow/kit/keys.js +7 -1
  114. package/src/flow/kit/logic_graph.js +97 -15
  115. package/src/flow/kit/references.js +0 -0
  116. package/src/flow/kit/settings_panel.js +0 -0
  117. package/src/flow/kit/settings_schema.js +2 -1
  118. package/src/flow/kit/step_picker.js +0 -0
  119. package/src/flow/kit/strings.js +3 -1
  120. package/src/flow/kit/value_picker.js +0 -0
  121. package/src/flow/kit/widgets.js +86 -109
  122. package/src/flow/lanes/editor.js +136 -14
  123. package/src/flow/lanes/index.js +3 -1
  124. package/src/flow/lanes/layout.js +0 -0
  125. package/src/flow/lanes/pipeline.js +44 -2
  126. package/src/flow/lanes/preview.js +0 -0
  127. package/src/flow/lanes/strings.js +1 -0
  128. package/src/flow/outline/editor.js +0 -0
  129. package/src/flow/outline/index.js +0 -0
  130. package/src/flow/outline/mapping.js +0 -0
  131. package/src/flow/outline/menu.js +0 -0
  132. package/src/flow/outline/operations.js +0 -0
  133. package/src/flow/outline/recognise.js +0 -0
  134. package/src/flow/outline/strings.js +0 -0
  135. package/src/help/help_modal.js +168 -42
  136. package/src/help/help_registry.js +12 -1
  137. package/src/host/external_links.js +0 -0
  138. package/src/host/file_picker.js +117 -0
  139. package/src/host/host.js +10 -2
  140. package/src/host/photino_host.js +9 -0
  141. package/src/host/photino_host.md +21 -3
  142. package/src/host/pywebview_host.js +10 -0
  143. package/src/tiles/chart_tiles.js +53 -245
  144. package/src/tiles/config_schema.js +8 -0
  145. package/src/tiles/figure_tile.js +322 -0
  146. package/src/tiles/layout_persistence.js +3 -3
  147. package/src/tiles/list_tiles.js +7 -7
  148. package/src/tiles/scope_picker.js +0 -0
  149. package/src/tiles/tile_base.js +1 -1
  150. package/src/tiles/tile_config_form.js +442 -0
  151. package/src/tiles/tile_grid.js +2 -0
  152. package/src/tiles/tile_registry.js +0 -0
  153. package/src/tiling/bottom_panel_tabs.js +67 -99
  154. package/src/tiling/command_palette.js +64 -19
  155. package/src/tiling/content_registry.js +4 -1
  156. package/src/tiling/desktops.js +11 -1
  157. package/src/tiling/entity_sources.js +0 -0
  158. package/src/tiling/keymap.js +403 -128
  159. package/src/tiling/kind_taxonomy.js +78 -0
  160. package/src/tiling/landing_table.js +0 -0
  161. package/src/tiling/loading_overlay.js +0 -0
  162. package/src/tiling/nav_panel.js +59 -10
  163. package/src/tiling/page_factory.js +5 -5
  164. package/src/tiling/panel_availability.js +49 -0
  165. package/src/tiling/panel_keys.js +0 -0
  166. package/src/tiling/shell.js +114 -12
  167. package/src/tiling/tab_strip.js +0 -0
  168. package/src/tiling/tile_breadcrumb.js +0 -0
  169. package/src/tiling/tile_renderer.js +105 -9
  170. package/src/tiling/tile_tab_menu.js +0 -0
  171. package/src/tiling/tile_tree.js +0 -0
  172. package/src/tiling/wm.js +562 -30
  173. package/src/tiling/zoom.js +0 -0
  174. package/src/ui/base/component_base.js +0 -0
  175. package/src/ui/base/controller_base.js +0 -0
  176. package/src/ui/base/page_base.js +0 -0
  177. package/src/ui/components/about_dialog.js +0 -0
  178. package/src/ui/components/action_dropdown.js +30 -2
  179. package/src/ui/components/alert_log.js +0 -0
  180. package/src/ui/components/alerts_pane.js +0 -0
  181. package/src/ui/components/attribute_list_editor.js +0 -0
  182. package/src/ui/components/autocomplete_field.js +0 -0
  183. package/src/ui/components/cell_editor_host.js +293 -0
  184. package/src/ui/components/cell_editors.js +480 -0
  185. package/src/ui/components/cell_grid.js +761 -0
  186. package/src/ui/components/cell_paste.js +243 -0
  187. package/src/ui/components/cell_selection.js +220 -0
  188. package/src/ui/components/choice_controls.js +351 -0
  189. package/src/ui/components/color_field.js +211 -0
  190. package/src/ui/components/color_list_field.js +210 -0
  191. package/src/ui/components/column_fit.js +0 -0
  192. package/src/ui/components/column_groups.js +314 -0
  193. package/src/ui/components/column_order.js +142 -0
  194. package/src/ui/components/computing_status_window.js +98 -25
  195. package/src/ui/components/confirm_dialog.js +81 -38
  196. package/src/ui/components/context_menu.js +2 -2
  197. package/src/ui/components/conversation_view.js +440 -0
  198. package/src/ui/components/crosstab.js +289 -0
  199. package/src/ui/components/data_table.js +696 -71
  200. package/src/ui/components/detail_header.js +22 -11
  201. package/src/ui/components/document_outline.js +397 -0
  202. package/src/ui/components/drag_reorder.js +0 -0
  203. package/src/ui/components/fact_table.js +0 -0
  204. package/src/ui/components/fill_handle.js +322 -0
  205. package/src/ui/components/gallery_picker.js +19 -8
  206. package/src/ui/components/header_actions.js +55 -0
  207. package/src/ui/components/inline_renamer.js +0 -0
  208. package/src/ui/components/job_progress.js +51 -0
  209. package/src/ui/components/managed_window.js +27 -4
  210. package/src/ui/components/menu_bar.js +745 -0
  211. package/src/ui/components/modal.js +449 -75
  212. package/src/ui/components/notification_history.js +3 -3
  213. package/src/ui/components/progress.js +483 -0
  214. package/src/ui/components/record_list.js +0 -0
  215. package/src/ui/components/row_activation.js +0 -0
  216. package/src/ui/components/section_stack.js +298 -0
  217. package/src/ui/components/series.js +173 -0
  218. package/src/ui/components/settings_view.js +634 -0
  219. package/src/ui/components/slide_out_panel.js +43 -6
  220. package/src/ui/components/slider_field.js +275 -18
  221. package/src/ui/components/sortable_list.js +0 -0
  222. package/src/ui/components/staged_edits.js +361 -0
  223. package/src/ui/components/staged_history.js +172 -0
  224. package/src/ui/components/table_filter_chips.js +0 -0
  225. package/src/ui/components/table_state_store.js +0 -0
  226. package/src/ui/components/table_structure.js +182 -0
  227. package/src/ui/components/table_values.js +0 -0
  228. package/src/ui/components/tabs.js +497 -0
  229. package/src/ui/components/tag_input.js +215 -0
  230. package/src/ui/components/toast.js +25 -8
  231. package/src/ui/components/toggle_field.js +175 -0
  232. package/src/ui/components/tree_view.js +55 -34
  233. package/src/ui/components/tsv.js +74 -0
  234. package/src/ui/components/window_taskbar.js +0 -0
  235. package/src/ui/components/wizard.js +563 -0
  236. package/src/ui/controllers/window_chrome_controller.js +2 -2
  237. package/src/ui/notification_center.js +375 -119
  238. package/src/ui/utils/auto_scrollbars.js +0 -0
  239. package/src/ui/utils/markdown.js +709 -0
  240. package/src/ui/utils/native_context_menu.js +0 -0
  241. package/src/ui/utils/overlay_scrollbar.js +16 -12
  242. package/src/ui/utils/raf_resize_observer.js +0 -0
  243. package/src/ui/utils/scroll_lock.js +0 -0
  244. package/src/ui/utils/strip_scroll.js +55 -0
  245. package/src/ui/utils/tooltip_service.js +0 -8
  246. package/tiles.js +27 -0
  247. package/widgets.js +69 -0
  248. package/wm.js +28 -0
  249. package/dist/chunk-6JSOVNID.js.map +0 -7
  250. package/dist/chunk-B5Q53LAJ.js.map +0 -7
  251. package/dist/chunk-FBGP5KN5.js.map +0 -7
  252. package/dist/chunk-FL5KFNQH.js.map +0 -7
  253. package/dist/chunk-NLTOY57M.js.map +0 -7
  254. package/dist/chunk-NNFTETK3.js +0 -633
  255. package/dist/chunk-NNFTETK3.js.map +0 -7
  256. package/dist/chunk-O5OHMWBB.js +0 -284
  257. package/dist/chunk-O5OHMWBB.js.map +0 -7
  258. package/dist/chunk-RQM5Z2MU.js.map +0 -7
  259. package/dist/chunk-SN4LSOAR.js.map +0 -7
  260. package/dist/chunk-W6FBJLPW.js +0 -367
  261. package/dist/chunk-W6FBJLPW.js.map +0 -7
  262. package/src/ui/controllers/panel_state_machine.js +0 -634
package/dist/tiles.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/tiles/config_schema.js", "../src/tiles/tile_base.js", "../src/tiles/chart_tiles.js", "../src/tiles/layout_persistence.js", "../src/tiles/list_tiles.js", "../src/tiles/scope_picker.js", "../src/tiles/tile_grid.js", "../tiles.js"],
4
- "sourcesContent": ["/**\n * config_schema.js\n *\n * Configuration schema definitions for widget types.\n * Defines field types, validation rules, and default values.\n */\n\n/**\n * Field type definitions for widget configuration.\n */\nexport const FieldTypes = {\n TEXT: 'text',\n NUMBER: 'number',\n CHECKBOX: 'checkbox',\n SELECT: 'select',\n MULTISELECT: 'multiselect',\n COLOR: 'color',\n RANGE: 'range'\n};\n\n/**\n * Validate a configuration value against its field schema.\n * @param {any} value - Value to validate\n * @param {Object} field - Field schema\n * @returns {{valid: boolean, error?: string}} Validation result\n */\nexport function validateField(value, field) {\n // Check required\n if (field.required && (value == null || value === '')) {\n return { valid: false, error: `${field.label} is required` };\n }\n\n // Type-specific validation\n switch (field.type) {\n case FieldTypes.NUMBER:\n case FieldTypes.RANGE:\n if (value != null && value !== '') {\n const num = parseFloat(value);\n if (isNaN(num)) {\n return { valid: false, error: `${field.label} must be a number` };\n }\n if (field.min != null && num < field.min) {\n return { valid: false, error: `${field.label} must be at least ${field.min}` };\n }\n if (field.max != null && num > field.max) {\n return { valid: false, error: `${field.label} must be at most ${field.max}` };\n }\n }\n break;\n\n case FieldTypes.SELECT:\n if (field.required && !value) {\n return { valid: false, error: `${field.label} must be selected` };\n }\n break;\n\n case FieldTypes.MULTISELECT:\n if (field.required && (!Array.isArray(value) || value.length === 0)) {\n return { valid: false, error: `${field.label} must have at least one selection` };\n }\n break;\n }\n\n return { valid: true };\n}\n\n/**\n * Validate an entire configuration object against a schema.\n * @param {Object} config - Configuration object\n * @param {Object} schema - Schema with fields array\n * @returns {{valid: boolean, errors: Object}} Validation result\n */\nexport function validateConfig(config, schema) {\n const errors = {};\n let valid = true;\n\n if (!schema?.fields) {\n return { valid: true, errors: {} };\n }\n\n schema.fields.forEach(field => {\n const result = validateField(config[field.key], field);\n if (!result.valid) {\n errors[field.key] = result.error;\n valid = false;\n }\n });\n\n return { valid, errors };\n}\n\n/**\n * Merge user config with defaults from schema.\n * @param {Object} config - User configuration\n * @param {Object} schema - Schema with fields array\n * @returns {Object} Merged configuration\n */\nexport function mergeWithDefaults(config, schema) {\n const result = { ...config };\n\n if (schema?.fields) {\n schema.fields.forEach(field => {\n if (result[field.key] === undefined && field.default !== undefined) {\n result[field.key] = field.default;\n }\n });\n }\n\n return result;\n}\n\n/**\n * Get options for a select/multiselect field.\n * Handles dynamic options (e.g., 'variables' which gets populated from data).\n * @param {Object} field - Field schema\n * @param {Object} data - Current data context\n * @returns {Array<{value: string, label: string}>} Options array\n */\nexport function getFieldOptions(field, data) {\n if (Array.isArray(field.options)) {\n return field.options;\n }\n\n // Dynamic options based on string identifier\n if (field.options === 'variables') {\n return getVariableOptions(data);\n }\n\n if (field.options === 'namespaces') {\n return getNamespaceOptions(data);\n }\n\n return [];\n}\n\n/**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n *\n * Examples:\n * \"Agriculture.__SimpleStocks__::arable_land[State]\" \u2192 \"arable_land\"\n * \"Population.population\" \u2192 \"population\"\n * \"Banks::Assets[Cash]\" \u2192 \"Assets / Cash\"\n * \"my_variable\" \u2192 \"my_variable\"\n *\n * @param {string} name - Raw variable key from analytics\n * @returns {string} Friendly display label\n */\nexport function formatVariableLabel(name) {\n if (!name) return '';\n let label = name;\n\n // Strip namespace prefix: \"Namespace.rest\" \u2192 \"rest\"\n const dotIdx = label.indexOf('.');\n if (dotIdx > 0) {\n label = label.slice(dotIdx + 1);\n }\n\n // Strip __SimpleStocks__:: or similar double-underscore sector prefixes\n label = label.replace(/^__\\w+__::/, '');\n\n // Handle Godley stock pattern: \"Sector::AccountType[Account]\" \u2192 \"AccountType / Account\"\n // But first strip [State] / [Rate] suffixes that are internal\n label = label.replace(/\\[State\\]$/i, '');\n label = label.replace(/\\[Rate\\]$/i, '');\n\n // Clean up trailing empty brackets or colons from stripping\n label = label.replace(/\\[\\]$/, '');\n\n // Replace :: with readable separator\n label = label.replace(/::/g, ' / ');\n\n // Replace single colons used as separators with underscore\n label = label.replace(/:/g, '_');\n\n // Clean up any double spaces or leading/trailing whitespace\n return label.replace(/\\s{2,}/g, ' ').trim();\n}\n\n/**\n * Get variable options from data.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string, category?: string}>} Variable options\n */\nexport function getVariableOptions(data) {\n const options = [];\n\n if (!data) return options;\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Stocks'\n });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Flows'\n });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Indicators'\n });\n });\n }\n\n return options;\n}\n\n/**\n * Extract unique namespace names from variable keys in data.\n * Stock keys follow the pattern \"Namespace.Sector::Type[Account]\".\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>}\n */\nexport function getNamespaceOptions(data) {\n const namespaces = new Set();\n const sources = [data?.stocks, data?.flows, data?.indicators];\n for (const source of sources) {\n if (!source) continue;\n for (const key of Object.keys(source)) {\n const dotIdx = key.indexOf('.');\n if (dotIdx > 0) {\n namespaces.add(key.slice(0, dotIdx));\n }\n }\n }\n if (namespaces.size === 0) namespaces.add('Main');\n return Array.from(namespaces).sort().map(ns => ({ value: ns, label: ns }));\n}\n\nexport default {\n FieldTypes,\n validateField,\n validateConfig,\n mergeWithDefaults,\n getFieldOptions,\n getVariableOptions,\n formatVariableLabel\n};\n", "/**\n * tile_base.js\n *\n * Base class for all dashboard widget tiles.\n * Provides common lifecycle management, tile chrome (header, config button),\n * and abstract methods for subclass implementation.\n */\n\nimport { openRawTracesWindow } from '../charts/plot_popout_window.js';\nimport { formatVariableLabel } from './config_schema.js';\n// The host is INJECTED, not fetched from a global.\n//\n// This imported `appHost()` from ui/js/ecoagent/app_host.js \u2014 a tile reaching into\n// the application to find out how to save a file. The framework is injection-only;\n// the app may have a root host provider, but the library does not get to know about\n// it. Its only use was to back \"Expand\" -> Export CSV/PNG, and a tile without a host\n// falls back to a Blob download, which is exactly what the host contract promises.\n\nexport class TileBase {\n /** @type {string} Widget type identifier - override in subclass */\n static TYPE = 'base';\n\n /** @type {string} Display title - override in subclass */\n static TITLE = 'Widget';\n\n /** @type {{w: number, h: number}} Default grid size - override in subclass */\n static DEFAULT_SIZE = { w: 4, h: 3 };\n\n /** @type {{minW: number, minH: number, maxW: number, maxH: number}} Size constraints */\n static SIZE_CONSTRAINTS = { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n /** @type {boolean} Whether widget can be expanded to a separate window - override in subclass */\n static EXPANDABLE = false;\n\n /** @type {boolean} Whether widget supports scenario comparison overlay - override in subclass */\n static SUPPORTS_COMPARISON = false;\n\n /**\n * @param {Object} options\n * @param {string} options.id - Unique tile identifier\n * @param {Object} options.grid - Parent TileGrid instance\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {Object} [options.config] - Widget-specific configuration\n * @param {boolean} [options.headless] - If true, mount without tile chrome (header, controls)\n * @param {{resolve: Function}} [options.dataSource] - Where this tile asks for its\n * own rows. Handed down by `TileGrid`; absent for a grid whose data is\n * broadcast with `setData()`, and then nothing ever calls `loadData()`.\n */\n constructor({ id, grid, eventBus = null, config = {}, readonly = false,\n headless = false, host = null, stateGuard = null,\n dataSource = null }) {\n this.host = host;\n // THE TILE PULLS; THE GRID DOES NOT PUSH.\n //\n // `TileGrid.setData()` broadcasts one dataset to every tile, which is the\n // right shape when every tile reads the same simulation run and the wrong\n // one when each tile is bound to a different query \u2014 the second tile would\n // then have to find its own rows inside a payload it never asked for. A\n // data source is anything answering `resolve(tileId, binding)`; the base\n // class only holds it and hands it to `loadData()`, so a grid constructed\n // without one behaves exactly as it did before this line existed, and the\n // broadcast path is untouched.\n this.dataSource = dataSource;\n // `window.__ECOSIM_JS_NEW__?.stateGuard` \u2014 an application's global, reached for\n // by a tile. The StateGuard is a FRAMEWORK service (@flexdesk/core); the INSTANCE is\n // the application's, and it is handed down through the grid. No guard => the\n // dataset writes happen directly, which is what the optional chain already did.\n this.stateGuard = stateGuard;\n this.id = id;\n this.grid = grid;\n this.eventBus = eventBus;\n this.config = { ...this.getDefaultConfig(), ...config };\n this.readonly = readonly;\n this.headless = headless;\n this.element = null;\n this.contentElement = null;\n this.chartInstance = null;\n this.data = null;\n /** @type {Object|null} Unfiltered analytics data for cross-namespace variable resolution */\n this.fullData = null;\n this._disposed = false;\n // Written by whatever implements `loadData()`. `_loadSeq` is the guard\n // against a slow first request landing after a fast second one and\n // painting stale rows over fresh ones \u2014 a tile is re-resolved on every\n // filter change, so that race is the normal case rather than the edge.\n this._lastLoadedAt = null;\n this._loadSeq = 0;\n /** @type {Map<string, {name: string, analytics: Object, color: string}>|null} */\n this.comparisonData = null;\n /** The board's scope (`TileGrid.setScope`), or null. Set before mount. */\n this.scope = null;\n }\n\n /**\n * Called when the board's scope changes (`TileGrid.setScope`), after\n * `this.scope` is set. A no-op here: a tile whose rows the grid's data\n * source loads is reloaded by the grid, and one fed through `setData` is\n * fed again by whoever owns its data.\n * @param {*} _scope\n */\n onScopeChange(_scope) {}\n\n /**\n * Set comparison data for overlay rendering.\n * Only meaningful for widgets where SUPPORTS_COMPARISON = true.\n * @param {Map<string, Object>|null} comparisonData\n */\n setComparisonData(comparisonData) {\n this.comparisonData = comparisonData;\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n * @param {string} name - Raw variable key\n * @returns {string} Friendly display label\n */\n formatLabel(name) {\n return formatVariableLabel(name);\n }\n\n /**\n * Look up the unit string for a variable from analytics metadata.\n * Checks stocks, flows, and indicators for unit metadata.\n * @param {string} varName - Variable name\n * @returns {string|null} Unit string or null\n */\n getVariableUnit(varName) {\n if (!varName || !this.data) return null;\n const sources = [this.data.stocks, this.data.flows, this.data.indicators];\n for (const source of sources) {\n const varData = source?.[varName];\n if (varData?.unit) return varData.unit;\n }\n return null;\n }\n\n /**\n * Look up a variable across stocks, flows, and indicators.\n * If the variable is not found, returns the first available variable\n * and updates the config key so the widget self-heals.\n * @param {Object} data - Analytics data\n * @param {string} configKey - Config property name (e.g. 'variable', 'xVariable')\n * @returns {{varData: any, varName: string}|null} Resolved data or null if no data at all\n */\n resolveVariable(data, configKey = 'variable') {\n const varName = this.config[configKey];\n if (varName) {\n // Try exact name first\n const varData = data.stocks?.[varName]\n || data.indicators?.[varName]\n || data.flows?.[varName];\n if (varData) return { varData, varName };\n\n // Try without namespace prefix (e.g. \"Population.population\" \u2192 \"population\")\n const dotIdx = varName.indexOf('.');\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const bareData = data.stocks?.[bare]\n || data.indicators?.[bare]\n || data.flows?.[bare];\n if (bareData) return { varData: bareData, varName: bare };\n }\n\n // Reverse lookup: bare name \u2192 namespace-prefixed key\n // e.g. \"population\" matches \"Population.population\" in MC data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n\n // Try unfiltered data (variable may be in a different namespace)\n if (this.fullData && this.fullData !== data) {\n const fullVarData = this.fullData.stocks?.[varName]\n || this.fullData.indicators?.[varName]\n || this.fullData.flows?.[varName];\n if (fullVarData) return { varData: fullVarData, varName };\n\n // Also try bare name against unfiltered data\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const fullBareData = this.fullData.stocks?.[bare]\n || this.fullData.indicators?.[bare]\n || this.fullData.flows?.[bare];\n if (fullBareData) return { varData: fullBareData, varName: bare };\n }\n\n // Reverse lookup against unfiltered data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [this.fullData.stocks, this.fullData.indicators, this.fullData.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n }\n }\n\n // Configured variable not found \u2014 auto-select the first available\n const sources = [data.stocks, data.indicators, data.flows];\n for (const source of sources) {\n if (!source) continue;\n const keys = Object.keys(source);\n if (keys.length > 0) {\n this.config[configKey] = keys[0];\n return { varData: source[keys[0]], varName: keys[0] };\n }\n }\n\n return null;\n }\n\n /**\n * Find a variable by name in data, trying exact match then suffix match.\n * Does NOT auto-fallback to first available variable.\n * @param {Object} data - Analytics data with stocks/indicators/flows\n * @param {string} varName - Variable name (bare or namespace-prefixed)\n * @returns {{varData: any, varName: string}|null}\n */\n static findVariable(data, varName) {\n if (!data || !varName) return null;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[varName]) return { varData: source[varName], varName };\n }\n // Reverse lookup: bare \"population\" \u2192 \"Population.population\"\n const dotIdx = varName.indexOf('.');\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n } else {\n // Strip prefix: \"Population.population\" \u2192 \"population\"\n const bare = varName.slice(dotIdx + 1);\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[bare]) return { varData: source[bare], varName: bare };\n }\n }\n return null;\n }\n\n /**\n * Get default configuration for this widget type.\n * Override in subclass.\n * @returns {Object} Default config object\n */\n getDefaultConfig() {\n return {};\n }\n\n /**\n * Get configuration schema for the config modal.\n * Override in subclass.\n * @returns {Object} Schema definition\n */\n getConfigSchema() {\n return { fields: [] };\n }\n\n /**\n * Render widget content with data.\n * Override in subclass.\n * @param {Object} data - Analytics data\n */\n render(data) {\n throw new Error('TileBase.render() must be implemented by subclass');\n }\n\n /**\n * Mount the tile into the container.\n * @param {HTMLElement} container - Parent container\n */\n mount(container) {\n if (this._disposed) return;\n\n this.element = document.createElement('div');\n this.element.className = `tile${this.readonly ? ' tile--readonly' : ''}`;\n\n // Use StateGuard bypass if available to set dataset properties\n const stateGuard = this.stateGuard;\n const setDataset = () => {\n this.element.dataset.tileId = this.id;\n this.element.dataset.tileType = this.constructor.TYPE;\n };\n if (stateGuard?.executeWithBypass) {\n stateGuard.executeWithBypass('tile-mount', setDataset);\n } else {\n setDataset();\n }\n\n if (this.headless) {\n // Headless mode: content only, no header/controls (for embedding in notebook cells)\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n this.element.appendChild(this.contentElement);\n } else {\n // Build tile chrome (header + content area)\n this._buildChrome();\n }\n\n container.appendChild(this.element);\n }\n\n /**\n * Update the widget with new data and/or config.\n * @param {Object} [data] - New analytics data\n * @param {Object} [config] - New config values to merge\n */\n update(data, config) {\n if (this._disposed) return;\n\n if (config) {\n const prevDocs = (this.config?.docs || '').trim();\n this.config = { ...this.config, ...config };\n const nextDocs = (this.config?.docs || '').trim();\n // Keep the header's info-button in sync with the docs state\n if (this.element && !this.headless && prevDocs !== nextDocs) {\n this._syncInfoButton();\n }\n }\n\n if (data !== undefined) {\n this.data = data;\n }\n\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /**\n * Load this tile's own data from `this.dataSource` and render it.\n *\n * A NO-OP HERE ON PURPOSE. The base class knows nothing about what a binding\n * is or what a dataset looks like \u2014 those belong to the consumer, and the\n * consumer that has them (Tables' `TablesTile`) implements this in ~30 lines\n * over `showLoading()` / `render()` / `showError()`. What upstream owns is the\n * CALL SITES: `TileGrid` invokes this after mount, after a resize settles and\n * after a config save, but only when a `dataSource` was injected. Making it a\n * hook rather than an implementation is what keeps EcoAgent's broadcast path\n * (`setData` -> `update`) bit-identical: with no data source nothing here ever\n * runs.\n *\n * @param {{force?: boolean}} [_opts] - `force` bypasses the source's cache.\n * @returns {Promise<void>}\n */\n async loadData(_opts = {}) {}\n\n /**\n * Called once after a drag-resize settles, for widgets whose content does not\n * reflow on its own \u2014 a Plotly figure sizes itself at draw time and stays that\n * size until something calls `Plotly.Plots.resize`. Deliberately NOT wired to a\n * ResizeObserver: the grid already knows when a resize ended, and an observer\n * per tile fires during the drag, which is a relayout per pointer-move.\n */\n onResize() {}\n\n /** Add, update, or remove the info (\u24D8) button in the header to match current docs state. */\n _syncInfoButton() {\n const header = this.element?.querySelector('.tile-header');\n const controls = header?.querySelector('.tile-controls');\n if (!controls) return;\n const docs = (this.config?.docs || '').trim();\n let btn = controls.querySelector('.tile-info-btn');\n if (docs) {\n if (!btn) {\n btn = document.createElement('button');\n btn.className = 'tile-info-btn twm-has-tooltip';\n btn.type = 'button';\n btn.tabIndex = -1;\n btn.style.cssText = 'background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;';\n btn.setAttribute('data-tooltip-placement', 'bottom');\n btn.setAttribute('data-tooltip-max-width', '420px');\n btn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>';\n btn.addEventListener('click', (e) => e.stopPropagation());\n const anchor = controls.querySelector('.tile-expand-btn')\n ?? controls.querySelector('.tile-remove-btn');\n if (anchor) controls.insertBefore(btn, anchor);\n else controls.appendChild(btn);\n }\n btn.setAttribute('data-tooltip', docs);\n } else if (btn) {\n btn.remove();\n }\n }\n\n /**\n * Clean up resources and remove from DOM.\n */\n dispose() {\n if (this._disposed) return;\n this._disposed = true;\n\n // Close expand window if open\n if (this._expandWindow?.isVisible) {\n this._expandWindow.close();\n }\n this._expandWindow = null;\n\n // Destroy chart instance if exists\n if (this.chartInstance) {\n this.chartInstance.destroy();\n this.chartInstance = null;\n }\n\n // Remove from DOM\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n\n this.element = null;\n this.contentElement = null;\n this.data = null;\n this.fullData = null;\n }\n\n /**\n * The entries in the tile's \u22EF menu, as `{action, label, icon, hidden}`.\n *\n * This existed as a LITERAL inside `_buildChrome`, and the literal was\n * EcoAgent's: \"Add to Documentation\" and \"Show in Documentation\". Both are\n * meaningful only for a tile whose `config.sourceCellId` names a notebook\n * cell, and the first one's hide condition is `sourceCellId && already-added` \u2014\n * so on a tile that has no `sourceCellId` at all it renders VISIBLE, and\n * choosing it emits `tile:add-to-documentation` at an application that has no\n * documentation. Every consumer other than EcoAgent therefore shipped a menu\n * item that did nothing, and could not remove it without editing this file.\n *\n * Returning `[]` drops the whole wrapper \u2014 button, dropdown and all \u2014 because\n * a \u22EF button that opens an empty menu reads as a broken feature rather than\n * an absent one. The default is the two entries above, so EcoAgent's chrome\n * is unchanged.\n *\n * Selection is routed through `_onMenuAction()`; override both together.\n * @returns {Array<{action: string, label: string, icon?: string, hidden?: boolean}>}\n */\n menuItems() {\n const linked = !!(this.config?.sourceCellId\n && this.grid?.documentationCellIds?.has(this.config.sourceCellId));\n return [\n { action: 'add-to-documentation',\n label: 'Add to Documentation', icon: 'post_add', hidden: linked },\n { action: 'show-in-documentation',\n label: 'Show in Documentation', icon: 'description', hidden: !linked },\n ];\n }\n\n /**\n * Act on a \u22EF menu selection. One dispatch point for every entry, so an\n * override of `menuItems()` cannot add a row that has nothing behind it, and\n * an unrecognised action is silently ignored rather than throwing into a\n * click handler.\n * @param {string} action\n * @protected\n */\n _onMenuAction(action) {\n if (action === 'add-to-documentation') {\n this.eventBus?.emit?.('tile:add-to-documentation', {\n tileType: this.constructor.TYPE,\n config: { ...this.config },\n });\n } else if (action === 'show-in-documentation') {\n if (this.config?.sourceCellId) {\n this.eventBus?.emit?.('tile:show-in-documentation', {\n sourceCellId: this.config.sourceCellId,\n });\n }\n }\n }\n\n /**\n * Build the tile chrome (header, content area, resize handles).\n * @private\n */\n _buildChrome() {\n // Header with drag handle and controls\n const header = document.createElement('div');\n header.className = 'tile-header';\n\n // Build controls HTML - expand button only if widget is expandable\n const expandBtnHtml = this.constructor.EXPANDABLE\n ? `<button class=\"tile-expand-btn twm-has-tooltip\" data-tooltip=\"Open in window\">\n <span class=\"material-symbols-outlined\">open_in_new</span>\n </button>`\n : '';\n\n // Info button \u2014 only shown if config.docs has text. Uses the\n // standard has-tooltip system so the docs appear as a hover tooltip\n // (auto-positioned) instead of a click-to-open popover.\n const docs = (this.config?.docs || '').trim();\n const infoBtnHtml = docs\n ? `<button class=\"tile-info-btn twm-has-tooltip\" type=\"button\" tabindex=\"-1\"\n data-tooltip=\"${this.#escapeAttr(docs)}\"\n data-tooltip-placement=\"bottom\"\n data-tooltip-max-width=\"420px\"\n style=\"background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;\">\n <span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>\n </button>`\n : '';\n\n // The \u22EF menu, from `menuItems()` rather than from a literal. Read-only\n // chrome never had one, so the hook is not even asked in that mode.\n const menuEntries = (this.readonly ? [] : this.menuItems()) ?? [];\n const menuHtml = menuEntries.length\n ? `<div class=\"tile-menu-wrapper\">\n <button class=\"tile-menu-btn twm-has-tooltip\" data-tooltip=\"More actions\">\n <span class=\"material-symbols-outlined\">more_vert</span>\n </button>\n <div class=\"tile-menu-dropdown\" hidden>\n ${menuEntries.map((item) => `\n <button class=\"tile-menu-item\" data-action=\"${this.#escapeAttr(item.action)}\"${item.hidden ? ' style=\"display:none\"' : ''}>\n ${item.icon ? `<span class=\"material-symbols-outlined\">${this.#escapeAttr(item.icon)}</span>` : ''}\n <span>${this.#escapeAttr(item.label ?? '')}</span>\n </button>`).join('')}\n </div>\n </div>`\n : '';\n\n if (this.readonly) {\n // Read-only mode: no drag handle, no menu, no remove button\n header.innerHTML = `\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n ${infoBtnHtml}\n ${expandBtnHtml}\n </div>\n `;\n } else {\n header.innerHTML = `\n <span class=\"tile-drag-handle twm-has-tooltip\" data-tooltip=\"Drag to reposition\">\n <span class=\"material-symbols-outlined\">drag_indicator</span>\n </span>\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n <button class=\"tile-config-btn twm-has-tooltip\" data-tooltip=\"Configure\">\n <span class=\"material-symbols-outlined\">settings</span>\n </button>\n ${menuHtml}\n ${infoBtnHtml}\n ${expandBtnHtml}\n <button class=\"tile-remove-btn twm-has-tooltip\" data-tooltip=\"Remove widget\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n `;\n }\n\n // Expand button handler\n const expandBtn = header.querySelector('.tile-expand-btn');\n expandBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onExpandClick();\n });\n\n // Info button is purely decorative \u2014 the docs are shown by the global\n // tooltip service via data-tooltip. Stop click-propagation so clicks\n // don't open the config panel, and make the button unfocusable.\n const infoBtn = header.querySelector('.tile-info-btn');\n infoBtn?.addEventListener('click', (e) => e.stopPropagation());\n\n if (!this.readonly) {\n // Config opens ONLY via the explicit cogwheel button \u2014 not a\n // title or content click, which fired the config panel too\n // eagerly (e.g. when you just wanted to read or pan the chart).\n const configBtn = header.querySelector('.tile-config-btn');\n configBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onConfigClick();\n });\n\n // \"...\" menu button + dropdown\n const menuBtn = header.querySelector('.tile-menu-btn');\n const menuDropdown = header.querySelector('.tile-menu-dropdown');\n if (menuBtn && menuDropdown) {\n menuBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const isOpen = !menuDropdown.hidden;\n menuDropdown.hidden = !menuDropdown.hidden;\n if (!isOpen) {\n // Close on outside click\n const closeMenu = (ev) => {\n if (!menuDropdown.contains(ev.target) && ev.target !== menuBtn) {\n menuDropdown.hidden = true;\n document.removeEventListener('pointerdown', closeMenu, true);\n }\n };\n // Delay to avoid immediate close from the same click\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', closeMenu, true);\n });\n }\n });\n // One listener per rendered entry, dispatching by `data-action`\n // into `_onMenuAction`. Wiring each action by name here is what\n // made the menu un-overridable: a subclass could add a row and\n // could not add the handler behind it.\n menuDropdown.querySelectorAll('.tile-menu-item').forEach((itemEl) => {\n itemEl.addEventListener('click', (e) => {\n e.stopPropagation();\n menuDropdown.hidden = true;\n this._onMenuAction(itemEl.dataset.action);\n });\n });\n }\n\n const removeBtn = header.querySelector('.tile-remove-btn');\n removeBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onRemoveClick();\n });\n }\n\n // Content area. Clicking the content no longer opens config \u2014 that\n // moved to the explicit cogwheel button in the header so chart\n // interaction (pan/zoom/hover) doesn't trip the config panel.\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n\n this.element.appendChild(header);\n this.element.appendChild(this.contentElement);\n\n if (!this.readonly) {\n // Resize handle (bottom-right)\n const resizeHandle = document.createElement('div');\n resizeHandle.className = 'tile-resize-handle se';\n resizeHandle.innerHTML = '<span class=\"material-symbols-outlined\">drag_handle</span>';\n this.element.appendChild(resizeHandle);\n\n // Context menu for \"Add to Documentation\" etc.\n this.element.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.eventBus?.emit?.('tile:context-menu', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n tileTitle: this.constructor.TITLE,\n config: { ...this.config },\n clientX: e.clientX,\n clientY: e.clientY,\n });\n });\n }\n }\n\n /**\n * Handle config button click \u2014 highlight tile and emit config request.\n * @private\n */\n _onConfigClick() {\n // Deselect all sibling tiles, then select this one\n this.element?.closest('.tile-grid')\n ?.querySelectorAll('.tile.tile--selected')\n .forEach(el => el.classList.remove('tile--selected'));\n this.element?.classList.add('tile--selected');\n\n // Emit event for grid/dashboard to show config panel\n this.eventBus?.emit?.('tile:config-request', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n });\n\n // Also dispatch DOM event for alternative handling\n this.element?.dispatchEvent(new CustomEvent('tile:config-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n }\n }));\n }\n\n /**\n * Handle remove button click.\n * @param {Event} [event] - Original click event\n * @private\n */\n _onRemoveClick(event) {\n const removeBtn = this.element?.querySelector('.tile-remove-btn');\n\n // Only dispatch DOM event - let the dashboard handle confirmation\n this.element?.dispatchEvent(new CustomEvent('tile:remove-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n anchorElement: removeBtn\n }\n }));\n }\n\n /**\n * Set the title displayed in the header.\n * @param {string} title - New title text\n */\n setTitle(title) {\n const titleEl = this.element?.querySelector('.tile-title');\n if (titleEl) {\n titleEl.textContent = title;\n }\n }\n\n /**\n * Show loading state in content area.\n */\n showLoading() {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-loading\">\n <span class=\"material-symbols-outlined spinning\">progress_activity</span>\n <span>Loading...</span>\n </div>\n `;\n }\n }\n\n /**\n * Show empty state in content area.\n *\n * The message is ESCAPED. Both this and `showError` interpolated straight\n * into `innerHTML`, and the string reaching `showError` is the one place a\n * caller has least control over \u2014 a server's error text, echoed back with a\n * column name or a filter value in it. Callers pass plain text; this decides\n * what that means in HTML.\n *\n * @param {string} [message] - Custom message\n */\n showEmpty(message = 'No data available') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-empty\">\n <span class=\"material-symbols-outlined\">inbox</span>\n <span>${this.#escapeAttr(message)}</span>\n </div>\n `;\n }\n }\n\n /**\n * Show error state in content area. The message is escaped \u2014 see `showEmpty`.\n * @param {string} [message] - Error message\n */\n showError(message = 'Failed to load data') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"twm-tile-error\">\n <span class=\"material-symbols-outlined\">error</span>\n <span>${this.#escapeAttr(message)}</span>\n </div>\n `;\n }\n }\n\n /**\n * Format a number for display.\n * @param {number} value - Number to format\n * @param {number} [decimals=2] - Decimal places\n * @returns {string} Formatted string\n */\n formatNumber(value, decimals = 2) {\n if (value == null || !Number.isFinite(value)) return '\u2014';\n\n const abs = Math.abs(value);\n if (abs >= 1e9) {\n return (value / 1e9).toFixed(1) + 'B';\n } else if (abs >= 1e6) {\n return (value / 1e6).toFixed(1) + 'M';\n } else if (abs >= 1e3) {\n return (value / 1e3).toFixed(1) + 'K';\n } else if (abs < 0.01 && abs > 0) {\n return value.toExponential(decimals);\n }\n return value.toFixed(decimals);\n }\n\n /**\n * Get available variables from data for config dropdowns.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>} Variable options\n */\n getAvailableVariables(data) {\n if (!data) return [];\n\n const variables = [];\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n variables.push({ value: name, label: name, category: 'Stocks' });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n variables.push({ value: name, label: name, category: 'Flows' });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n variables.push({ value: name, label: name, category: 'Indicators' });\n });\n }\n\n return variables;\n }\n\n // =========================================================================\n // EXPAND WINDOW FUNCTIONALITY\n // Reuses PlotPopoutWindow's patterns and CSS classes\n // =========================================================================\n\n /**\n * Handle expand button click.\n * @private\n */\n _onExpandClick() {\n if (!this.constructor.EXPANDABLE) return;\n\n const expandData = this.getExpandData();\n if (!expandData) {\n console.warn(`[TileBase] No expand data from widget ${this.id}`);\n return;\n }\n\n this._openExpandWindow(expandData);\n }\n\n /**\n * Get data for the expanded window.\n * Override in subclass for expandable widgets.\n * @returns {Object|null} { title, traces, layout, tableHeaders, tableRows }\n */\n getExpandData() {\n return null;\n }\n\n /**\n * Open the expand window with plot and data tabs.\n * Delegates to openRawTracesWindow (PlotPopoutWindow module) which\n * provides proper toolbar layout, download buttons, and data table.\n * @param {Object} expandData - Data from getExpandData()\n * @private\n */\n async _openExpandWindow(expandData) {\n if (this._expandWindow?.isVisible) {\n this._expandWindow.bringToFront();\n return;\n }\n\n this._expandWindow = await openRawTracesWindow({\n host: this.host,\n id: `tile-expand-${this.id}`,\n title: expandData.title || this.constructor.TITLE,\n traces: expandData.traces,\n layout: expandData.layout,\n frames: expandData.frames,\n tableHeaders: expandData.tableHeaders,\n tableRows: expandData.tableRows,\n services: { eventBus: this.eventBus },\n });\n }\n\n /**\n * Escape a string for safe insertion into HTML \u2014 an attribute value or a text\n * node, since the five characters that matter are the same five in both.\n * @private\n */\n #escapeAttr(s) {\n return String(s ?? '').replace(/[&<>\"']/g, c => ({\n '&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'\n }[c]));\n }\n\n /**\n * Show toast notification via eventBus.\n * @private\n */\n _notify(title, message, severity = 'info') {\n this.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n}\n\nexport default TileBase;\n", "/**\n * chart_tiles.js \u2014 a CHART tile and a KPI tile for a `TileGrid`.\n *\n * Lifted from Tables' dashboard widgets (`tables.chart`, `tables.kpi`), with the\n * Tables half left behind: no binding, no Dataset, no column types, no currency\n * refusals. A tile here is handed ALREADY-COMPUTED series through `setData()`;\n * turning records into series is the embedder's job, because only the embedder\n * knows what a record is.\n *\n * import { registerChartTiles } from '@flexdesk/tiles';\n * registerChartTiles(); // idempotent; nothing registers at import\n * const tile = grid.addTile('flexdesk.chart', {x: 0, y: 0, w: 6, h: 4},\n * { chart_type: 'line', title: 'Burndown', unit: 'pts' });\n * tile.setData({\n * series: [\n * { x: days, y: remaining, name: 'Remaining', interpolation: 'step' },\n * { x: days, y: ideal, name: 'Ideal', lineStyle: 'dashed' },\n * ],\n * markers: [{ x: today, label: 'Today' }],\n * note: 'Points from 41 stories',\n * });\n *\n * \u2550\u2550 THE DATA A CHART TILE TAKES \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 * { series: [{x, y, name, color?, lineStyle?, interpolation?, line?, customdata?}],\n * markers?: [{x, label?, color?, lineStyle?}], vertical lines (buildOverlayShapes)\n * referenceLines?: [{value, label?, \u2026}], horizontal lines, passed through\n * xKind?: 'date' | 'number' | 'category', inferred from x when absent\n * note?: string } a line under the figure\n *\n * Shorthands: an ARRAY is `{series: array}`; a single `{x, y}`, `{labels, values}`\n * or `{values}` object is one series. Pie, donut and funnel read `labels`/`values`\n * (or `x`/`y`) of the first series; a histogram reads `values` (or `y`/`x`) of\n * each. `line` on a series is merged over the built `trace.line`, so\n * `line: {shape: 'hv', dash: 'dash'}` is as good as `interpolation`/`lineStyle`.\n *\n * \u2550\u2550 WHY THE DRAW HAS ITS OWN TRY/CATCH, AND A SEQUENCE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * The draw is `await ensurePlotly()` deep, so `render()` returns long before\n * anything can throw. `_draw` therefore reports its own failures (Plotly\n * absent included \u2014 a clear error state, never an unhandled rejection), and\n * `_drawSeq` discards a draw that lands after a newer one.\n *\n * EVERY STATE CHANGE INVALIDATES THE FIGURE. `showEmpty`, `showLoading` and\n * `showError` replace the content with `innerHTML`, which detaches the Plotly div\n * without telling Plotly. So each of them here first purges the figure, drops the\n * reference, marks it not drawn, and bumps `_drawSeq` \u2014 and a draw still in\n * flight when `setData(empty)` arrives finds itself stale and purges its own\n * figure instead of marking it drawn.\n *\n * `scrollZoom` is off per call: a tile sits on a scrolling board, and the wheel\n * over a chart must scroll past it rather than zoom it.\n */\n\nimport { TileBase } from './tile_base.js';\nimport { registerWidget, getWidget } from './tile_registry.js';\nimport {\n buildTrace, buildXAxisLayout, buildYAxisLayout, buildLegendLayout,\n buildHistogramTrace, buildOverlayShapes,\n} from '../charts/chart_types.js';\nimport {\n createChart, resize as resizePlot, purge, ensurePlotly, getSeriesColor,\n} from '../charts/plotly_wrapper.js';\nimport { strideDownsampleShared } from '../charts/downsample.js';\n\n/** Part-of-whole types: one series, no axes. */\nconst CATEGORICAL_ONLY = new Set(['pie', 'donut', 'funnel']);\n\n/** Every type the chart tile draws. */\nexport const CHART_TILE_TYPES = Object.freeze([\n { value: 'line', label: 'Line' },\n { value: 'bar', label: 'Bar' },\n { value: 'bar-stacked', label: 'Bar (stacked)' },\n { value: 'bar-horizontal', label: 'Bar (horizontal)' },\n { value: 'area', label: 'Area' },\n { value: 'area-stacked', label: 'Area (stacked %)' },\n { value: 'scatter', label: 'Scatter' },\n { value: 'pie', label: 'Pie' },\n { value: 'donut', label: 'Donut' },\n { value: 'funnel', label: 'Funnel' },\n { value: 'histogram', label: 'Histogram' },\n]);\n\nconst AXIS_CHARTS = ['bar', 'bar-stacked', 'bar-horizontal', 'line', 'area', 'area-stacked', 'scatter'];\n\n/**\n * THE DISPLAY SETTINGS EACH CHART TYPE READS, and the only place that says so:\n * the config schema shows a setting for exactly these types and the draw reads\n * it for no others, so a hidden setting a config still carries cannot go on\n * changing the figure unseen.\n */\nconst READS = Object.freeze({\n legend: new Set([...AXIS_CHARTS, 'pie', 'donut', 'histogram']),\n axis_titles: new Set([...AXIS_CHARTS, 'histogram']),\n y_scale: new Set(['bar', 'bar-horizontal', 'line', 'area', 'scatter']),\n y_range: new Set(['bar', 'bar-stacked', 'bar-horizontal', 'line', 'area', 'scatter']),\n show_markers: new Set(['line', 'area', 'area-stacked']),\n});\n\n/** Room for the tile's own header, and none for a Plotly title never set. */\nconst TILE_MARGIN = { l: 48, r: 16, t: 8, b: 36 };\n\n/** The point count above which a continuous series is decimated \u2014 a rendering\n * budget, not a data limit. */\nconst MAX_POINTS = 2000;\n\n/**\n * Normalise what `setData` was handed into `{series, markers, referenceLines,\n * xKind, note}`, or `null` when there is nothing to draw. Exported for tests\n * and for an embedder that wants to know what the tile will make of its data.\n */\nexport function normalizeChartData(data) {\n if (data == null) return null;\n let d = data;\n if (Array.isArray(d)) d = { series: d };\n else if (typeof d !== 'object') return null;\n else if (!Array.isArray(d.series)) {\n const single = ['x', 'y', 'labels', 'values'].some((k) => Array.isArray(d[k]));\n d = { ...d, series: single ? [d] : [] };\n }\n const series = d.series.filter((s) => s && pointCount(s) > 0);\n if (!series.length) return null;\n return {\n series,\n markers: Array.isArray(d.markers) ? d.markers : [],\n referenceLines: Array.isArray(d.referenceLines) ? d.referenceLines : [],\n xKind: d.xKind || null,\n note: typeof d.note === 'string' ? d.note : '',\n };\n}\n\nfunction pointCount(s) {\n for (const k of ['y', 'values', 'x', 'labels']) {\n if (Array.isArray(s[k])) return s[k].length;\n }\n return 0;\n}\n\nexport class ChartTile extends TileBase {\n static TYPE = 'flexdesk.chart';\n static TITLE = 'Chart';\n static ICON = 'insert_chart';\n static DESCRIPTION = 'Line, bar, area, pie, donut, funnel or histogram over series you supply.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 3, maxW: 12, maxH: 10 };\n\n /**\n * @param {Object} options - TileBase's, plus:\n * @param {Function} [options.onPointClick] - `({customdata, point, tile})`\n * on a click on a mark. Also assignable later as `tile.onPointClick`.\n */\n constructor(options = {}) {\n super(options);\n this.onPointClick = typeof options.onPointClick === 'function' ? options.onPointClick : null;\n this._plotEl = null;\n this._drawn = false;\n this._drawSeq = 0;\n }\n\n /** Pure and static-only \u2014 it runs inside `TileBase`'s constructor. */\n getDefaultConfig() {\n return {\n title: '',\n chart_type: 'line',\n unit: '',\n legend: 'bottom',\n x_title: '',\n y_title: '',\n y_scale: 'linear',\n y_min: null,\n y_max: null,\n show_markers: false,\n max_points: MAX_POINTS,\n };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { name: 'title', type: 'text', label: 'Tile title' },\n { name: 'chart_type', type: 'select', label: 'Chart type',\n options: CHART_TILE_TYPES.map((o) => ({ ...o })) },\n { name: 'unit', type: 'text', label: 'Unit',\n help: 'Shown with the value axis title, e.g. \"pts\" or \"h\".' },\n { name: 'legend', type: 'select', label: 'Legend',\n visibleWhen: { field: 'chart_type', in: [...READS.legend] },\n options: [\n { value: 'bottom', label: 'Below' },\n { value: 'top', label: 'Above' },\n { value: 'right', label: 'Right' },\n { value: 'left', label: 'Left' },\n { value: 'hidden', label: 'None' },\n ] },\n { name: 'x_title', type: 'text', label: 'X axis title',\n visibleWhen: { field: 'chart_type', in: [...READS.axis_titles] } },\n { name: 'y_title', type: 'text', label: 'Y axis title',\n visibleWhen: { field: 'chart_type', in: [...READS.axis_titles] } },\n { name: 'y_scale', type: 'select', label: 'Y scale',\n visibleWhen: { field: 'chart_type', in: [...READS.y_scale] },\n options: [{ value: 'linear', label: 'Linear' }, { value: 'log', label: 'Logarithmic' }] },\n { name: 'y_min', type: 'number', label: 'Y minimum',\n visibleWhen: { field: 'chart_type', in: [...READS.y_range] } },\n { name: 'y_max', type: 'number', label: 'Y maximum',\n visibleWhen: { field: 'chart_type', in: [...READS.y_range] } },\n { name: 'show_markers', type: 'checkbox', label: 'Show point markers',\n visibleWhen: { field: 'chart_type', in: [...READS.show_markers] } },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n }\n\n /**\n * `null` here is \"the grid has no data\", not \"clear this tile\": TileGrid's\n * config save calls `update(grid.data, newConfig)`, and a grid whose tiles\n * are fed one by one through `setData` has `grid.data === null` \u2014 passed on,\n * it would drop the tile's series and skip the redraw in the new chart type.\n * `setData(null)` is how a tile is cleared.\n */\n update(data, config) {\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n }\n\n /**\n * Hand this tile its series. Unlike `update()`, an empty or null value is\n * drawn \u2014 as the empty state \u2014 rather than ignored.\n */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n /**\n * Kick off the draw and return. Deliberately not `async`: nothing awaits\n * `render`, so a returned promise would be a rejection nobody catches.\n */\n render(data) {\n this._draw(data);\n }\n\n /** One relayout when a resize settles; nothing while a draw is in flight. */\n onResize() {\n if (!this._plotEl || !this._drawn) return;\n resizePlot(this._plotEl).catch(() => {});\n }\n\n menuItems() {\n return [{ action: 'download-png', label: 'Download PNG', icon: 'image' }];\n }\n\n _onMenuAction(action) {\n if (action === 'download-png') this._downloadPng();\n }\n\n // \u2500\u2500 the three states: each one invalidates the figure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n showLoading() {\n this._invalidate();\n super.showLoading();\n }\n\n showEmpty(message) {\n this._invalidate();\n super.showEmpty(message);\n }\n\n showError(message) {\n this._invalidate();\n super.showError(message);\n }\n\n /** Release the figure BEFORE the element goes \u2014 `TileBase.dispose` nulls it. */\n dispose() {\n this._invalidate();\n super.dispose();\n }\n\n /** Any draw in flight is now stale, and the figure on screen is released. */\n _invalidate() {\n this._drawSeq += 1;\n this._releasePlot();\n }\n\n /** Hand the current figure back to Plotly and forget it. Idempotent, and\n * not awaited: a rejected purge (Plotly absent, already purged) must not\n * surface as an unhandled rejection. */\n _releasePlot() {\n const el = this._plotEl;\n this._plotEl = null;\n this._drawn = false;\n if (el) purge(el).catch(() => {});\n }\n\n // \u2500\u2500 the draw \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _draw(data) {\n this._drawSeq += 1;\n const seq = this._drawSeq;\n const content = this.contentElement;\n if (!content) return;\n\n // Every path below replaces the content, so the figure there now is\n // about to be orphaned whichever way this goes.\n this._releasePlot();\n\n const norm = normalizeChartData(data);\n if (!norm) { this.showEmpty('No data to show.'); return; }\n\n let plan;\n try {\n plan = this._plan(norm);\n } catch (err) {\n this._failed(err);\n return;\n }\n if (!plan) return; // `_plan` has already said why\n\n const host = document.createElement('div');\n host.className = 'fd-chart-tile';\n const parts = [host];\n if (norm.note) {\n const note = document.createElement('div');\n note.className = 'fd-chart-tile__note';\n note.setAttribute('role', 'note');\n note.textContent = norm.note;\n note.title = norm.note;\n parts.push(note);\n }\n content.replaceChildren(...parts);\n this._plotEl = host;\n this._drawn = false;\n\n try {\n await createChart(host, plan.traces, plan.layout, {\n scrollZoom: false,\n displayModeBar: false,\n responsive: true,\n });\n } catch (err) {\n if (this._disposed || seq !== this._drawSeq) return;\n this._failed(err);\n return;\n }\n if (this._disposed || seq !== this._drawSeq) {\n // A newer draw or a state change has already replaced the content;\n // this figure is detached, and purging it releases its listeners.\n purge(host).catch(() => {});\n return;\n }\n this._drawn = true;\n this._wireClick(host);\n }\n\n /** Plotly's click, reduced to the point's own `customdata`. A pie's point\n * carries its slice index as `pointNumber` (older builds: `pointIndex`),\n * and its `customdata` is read off the trace by that index. */\n _wireClick(host) {\n if (typeof host.on !== 'function') return;\n host.on('plotly_click', (ev) => {\n const point = ev?.points?.[0];\n if (!point || typeof this.onPointClick !== 'function') return;\n const trace = point.data || {};\n let customdata = point.customdata;\n if (trace.type === 'pie' || customdata === undefined) {\n const i = point.pointNumber ?? point.pointIndex;\n if (Array.isArray(trace.customdata) && i != null) customdata = trace.customdata[i];\n }\n try {\n this.onPointClick({ customdata, point, tile: this });\n } catch (err) {\n console.error('[ChartTile] onPointClick threw:', err);\n }\n });\n }\n\n /**\n * Turn normalised data into `{traces, layout}`, or put the tile in the\n * empty state and answer `null`.\n */\n _plan(norm) {\n const type = this.config.chart_type || 'line';\n const { series } = norm;\n\n if (CATEGORICAL_ONLY.has(type)) {\n // ONE series. A pie of three is three pies drawn on top of one another.\n const s = series[0];\n const labels = s.labels ?? s.x ?? [];\n const values = s.values ?? s.y ?? [];\n const trace = buildTrace({\n chartType: type,\n x: labels.map((v) => (v === null || v === undefined ? '\u2014' : String(v))),\n y: values,\n name: s.name || '',\n colors: s.colors || null,\n });\n if (Array.isArray(s.customdata)) trace.customdata = s.customdata;\n return {\n traces: [trace],\n layout: {\n margin: type === 'funnel' ? { ...TILE_MARGIN, l: 96 } : TILE_MARGIN,\n ...this._legend(),\n },\n };\n }\n\n if (type === 'histogram') {\n const traces = series.map((s, i) => {\n const raw = s.values ?? s.y ?? s.x ?? [];\n const trace = {\n ...buildHistogramTrace({\n x: raw.map(toNumber).filter((v) => v !== null),\n color: s.color || getSeriesColor(i),\n name: s.name || `Series ${i + 1}`,\n ...(s.nbins ? { nbins: s.nbins } : {}),\n }),\n opacity: series.length > 1 ? 0.7 : 1,\n };\n return trace;\n });\n return {\n traces,\n layout: {\n margin: TILE_MARGIN, ...this._legend(), barmode: 'overlay',\n xaxis: buildXAxisLayout({ title: this.config.x_title || '' }),\n yaxis: buildYAxisLayout({ axisId: 'yaxis', title: this.config.y_title || 'Count' }),\n },\n };\n }\n\n const kind = norm.xKind || inferXKind(series);\n const base = type.startsWith('bar') ? 'bar' : type;\n const target = Number(this.config.max_points) || MAX_POINTS;\n const showMarkers = READS.show_markers.has(type) && this.config.show_markers === true;\n\n const traces = series.map((s, i) => {\n let x = Array.isArray(s.x) ? s.x : (s.y || []).map((_, j) => j);\n let y = Array.isArray(s.y) ? s.y : (s.values || []);\n let customdata = Array.isArray(s.customdata) ? s.customdata : null;\n if (kind !== 'category') {\n const cut = strideDownsampleShared(x, customdata ? { y, customdata } : { y }, target);\n x = cut.time;\n y = cut.series.y;\n if (customdata) customdata = cut.series.customdata;\n }\n const trace = buildTrace({\n chartType: base,\n x,\n y,\n name: s.name || `Series ${i + 1}`,\n color: s.color || null,\n lineStyle: s.lineStyle || 'solid',\n interpolation: s.interpolation || 'linear',\n ...(s.lineWidth ? { lineWidth: s.lineWidth } : {}),\n seriesIndex: i,\n showMarkers,\n });\n if (s.line && typeof s.line === 'object') trace.line = { ...(trace.line || {}), ...s.line };\n if (customdata) trace.customdata = customdata;\n return trace;\n });\n\n const xaxis = buildXAxisLayout({ title: this.config.x_title || '', scaleType: 'linear' });\n if (kind !== 'number') xaxis.type = kind === 'date' ? 'date' : 'category';\n\n const log = READS.y_scale.has(type) && this.config.y_scale === 'log';\n const yaxis = buildYAxisLayout({\n axisId: 'yaxis',\n title: this._valueTitle(series),\n scaleType: log ? 'log' : 'linear',\n min: READS.y_range.has(type) ? axisBound(this.config.y_min, log) : null,\n max: READS.y_range.has(type) ? axisBound(this.config.y_max, log) : null,\n });\n\n const layout = { margin: TILE_MARGIN, xaxis, yaxis, ...this._legend() };\n if (type === 'bar') layout.barmode = 'group';\n if (type === 'bar-stacked') layout.barmode = 'stack';\n if (type === 'bar-horizontal') {\n // Swap the DATA and the AXES together; swapping one draws NaN.\n layout.barmode = 'group';\n for (const t of traces) { [t.x, t.y] = [t.y, t.x]; t.orientation = 'h'; }\n [layout.xaxis, layout.yaxis] = [yaxis, xaxis];\n layout.margin = { ...TILE_MARGIN, l: 96 };\n }\n\n const overlay = buildOverlayShapes({\n verticalLines: type === 'bar-horizontal' ? [] : norm.markers,\n referenceLines: norm.referenceLines,\n });\n if (overlay.shapes.length) layout.shapes = overlay.shapes;\n if (overlay.annotations.length) layout.annotations = overlay.annotations;\n return { traces, layout };\n }\n\n /** The value axis title: the configured one, else the single series' name,\n * with the unit beside it. */\n _valueTitle(series) {\n const unit = (this.config.unit || '').trim();\n const base = this.config.y_title || (series.length === 1 ? (series[0].name || '') : '');\n if (!unit) return base;\n return base ? `${base} (${unit})` : unit;\n }\n\n /**\n * `showlegend` and `legend`, lifted out by name: `buildLegendLayout`'s\n * top-level `font` would replace the theme's whole font object. Below the\n * plot it is anchored to the CONTAINER, so the axis title sits above it\n * however tall the tick labels are.\n */\n _legend() {\n if (!READS.legend.has(this.config.chart_type || 'line')) return { showlegend: false };\n const position = this.config.legend || 'bottom';\n const spec = buildLegendLayout(position);\n const out = { showlegend: spec.showlegend === true };\n if (spec.legend) out.legend = spec.legend;\n if (position === 'bottom' && out.legend) {\n out.legend = { ...out.legend, yref: 'container', y: 0, yanchor: 'bottom' };\n }\n return out;\n }\n\n async _downloadPng() {\n if (!this._plotEl || !this._drawn) return;\n try {\n const P = await ensurePlotly();\n const uri = await P.toImage(this._plotEl, { format: 'png', scale: 2 });\n const filename = `${slug(this.config.title || this.constructor.TITLE)}.png`;\n // The native Save dialog when the host has one (a desktop window).\n // `saveFile` answers null when there is no dialog behind it, which\n // means \"download it yourself\", not a failed save.\n const dialogs = this.host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: uri.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) this._notify('Download', `Chart saved to ${result.path}`, 'success');\n else if (!result.cancelled) this._notify('Download failed', result.error || 'The image could not be saved', 'error');\n return;\n }\n const a = document.createElement('a');\n a.href = uri;\n a.download = filename;\n a.click();\n } catch (err) {\n this._notify('Download failed', `The image could not be made: ${err?.message || err}`, 'error');\n }\n }\n\n _failed(err) {\n if (this._disposed) return;\n this.showError(`This chart could not be drawn: ${err?.message || err}`);\n this.eventBus?.emit?.('tile:render-failed', {\n tileId: this.id,\n message: err?.message || String(err),\n });\n }\n}\n\n/**\n * ONE NUMBER, AND WHAT IT IS DOING. Plain DOM, no Plotly: a KPI strip is the\n * common board, and it should not pay 4 MB for three divs \u2014 nor wait for them.\n * It therefore renders synchronously and renders without Plotly loaded at all.\n *\n * tile.setData({ value: 42, reference: 37, label: 'Open bugs', note: 'vs last week' })\n *\n * A bare number is `{value}`. The delta's ARROW states the fact (up or down);\n * `invert_delta` flips only the colour's judgement, so a falling cost is a\n * green \u25BC. The sign is in the text too, because colour alone does not survive\n * a monochrome display.\n */\nexport class KpiTile extends TileBase {\n static TYPE = 'flexdesk.kpi';\n static TITLE = 'KPI';\n static ICON = 'speed';\n static DESCRIPTION = 'One number with a label and an optional comparison.';\n static DEFAULT_SIZE = { w: 3, h: 2 };\n static SIZE_CONSTRAINTS = { minW: 2, minH: 2, maxW: 12, maxH: 6 };\n\n getDefaultConfig() {\n return {\n title: '',\n label: '',\n unit: '',\n format: 'number',\n decimals: null,\n prefix: '',\n suffix: '',\n currency: null,\n delta_relative: false,\n invert_delta: false,\n foot: '',\n };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { name: 'title', type: 'text', label: 'Tile title' },\n { name: 'label', type: 'text', label: 'Label' },\n { name: 'unit', type: 'text', label: 'Unit', help: 'Shown after the number, e.g. \"pts\".' },\n { name: 'format', type: 'select', label: 'Format',\n options: [\n { value: 'number', label: 'Number' },\n { value: 'percent', label: 'Percentage (of a ratio)' },\n { value: 'currency', label: 'Currency' },\n { value: 'duration', label: 'Duration (seconds)' },\n { value: 'text', label: 'Text' },\n ] },\n { name: 'decimals', type: 'number', label: 'Decimals', min: 0, max: 6 },\n { name: 'currency', type: 'text', label: 'Currency code',\n help: 'ISO 4217, e.g. EUR. Left empty, the number is shown without a symbol.' },\n { name: 'prefix', type: 'text', label: 'Prefix' },\n { name: 'suffix', type: 'text', label: 'Suffix' },\n { name: 'delta_relative', type: 'checkbox', label: 'Show the change as a percentage' },\n { name: 'invert_delta', type: 'checkbox', label: 'A fall is good',\n help: 'For a cost, a queue length or a latency: a smaller number is the better one.' },\n { name: 'foot', type: 'text', label: 'Caption' },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n }\n\n /** `null` is \"the grid has no data\" \u2014 see `ChartTile.update`. And a value of\n * `0` is a value: `TileBase.update` re-renders truthy data only. */\n update(data, config) {\n if (this._disposed) return;\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n const d = this.data;\n if (d !== null && d !== undefined && !d && this.contentElement) this.render(d);\n }\n\n /** `{value, reference?, label?, note?}` or a bare number; null is the empty state. */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n render(data) {\n const content = this.contentElement;\n if (!content) return;\n const d = typeof data === 'number' ? { value: data } : data;\n if (!d || typeof d !== 'object' || d.value === null || d.value === undefined || d.value === '') {\n this.showEmpty('No value to show.');\n return;\n }\n\n content.replaceChildren();\n const box = document.createElement('div');\n box.className = 'fd-kpi';\n\n const labelText = d.label || this.config.label || '';\n if (labelText) {\n const label = document.createElement('div');\n label.className = 'fd-kpi__label';\n label.textContent = labelText;\n label.title = labelText;\n box.append(label);\n }\n\n const big = document.createElement('div');\n big.className = 'fd-kpi__value';\n big.textContent = this._format(d.value, true);\n big.title = String(d.value);\n box.append(big);\n\n const delta = this._buildDelta(d.value, d.reference);\n if (delta) box.append(delta);\n\n const foot = [this.config.foot, d.note].filter(Boolean).join(' \u00B7 ');\n if (foot) {\n const el = document.createElement('div');\n el.className = 'fd-kpi__foot';\n el.textContent = foot;\n el.title = foot;\n box.append(el);\n }\n content.append(box);\n }\n\n /** The comparison line, or `null` when there is nothing to compare against.\n * `0` is a real reference \u2014 the test is finiteness, never truthiness. */\n _buildDelta(rawValue, rawReference) {\n const value = Number(rawValue);\n if (rawReference === null || rawReference === undefined || rawReference === '') return null;\n const reference = Number(rawReference);\n if (!Number.isFinite(value) || !Number.isFinite(reference)) return null;\n\n const change = value - reference;\n const el = document.createElement('div');\n el.className = 'fd-kpi__delta';\n // No change gets neither colour: a flat week is not a good one.\n if (change > 0) el.classList.add(this.config.invert_delta ? 'fd-kpi__delta--down' : 'fd-kpi__delta--up');\n else if (change < 0) el.classList.add(this.config.invert_delta ? 'fd-kpi__delta--up' : 'fd-kpi__delta--down');\n\n const arrow = change > 0 ? '\u25B2' : change < 0 ? '\u25BC' : '\u2013';\n const magnitude = this.config.delta_relative\n ? (reference === 0 ? null : formatValue(Math.abs(change / reference), {\n format: 'percent', decimals: this.config.decimals ?? 1 }))\n : this._format(Math.abs(change), false);\n const sign = change > 0 ? '+' : change < 0 ? '-' : '';\n el.textContent = magnitude === null ? `${arrow} \u2014` : `${arrow} ${sign}${magnitude}`;\n el.title = `Compared with ${this._format(reference, false)}`;\n return el;\n }\n\n _format(value, withAffixes) {\n const format = this.config.format || 'number';\n const body = formatValue(value, {\n format: format === 'text' && !withAffixes ? 'number' : format,\n decimals: this.config.decimals,\n currency: this.config.currency,\n prefix: withAffixes ? this.config.prefix : '',\n suffix: withAffixes ? this.config.suffix : '',\n });\n const unit = (this.config.unit || '').trim();\n return unit && body !== '\u2014' ? `${body} ${unit}` : body;\n }\n}\n\n/**\n * Register both tiles. Idempotent: a second call registers nothing new and\n * replaces nothing \u2014 and nothing registers at import time, so an app that\n * imports `@flexdesk/tiles` without wanting these never sees them in its\n * Add-widget catalogue.\n */\nexport function registerChartTiles() {\n for (const Tile of [ChartTile, KpiTile]) {\n if (getWidget(Tile.TYPE) !== Tile) registerWidget(Tile);\n }\n}\n\n// \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\u2500\u2500\u2500\u2500\u2500\n\n/** The header shows `config.title`, else the type's own title. */\nfunction applyTitle(tile) {\n tile.setTitle(tile.config.title || tile.constructor.TITLE);\n}\n\n/** `'date' | 'number' | 'category'` from the x values themselves. */\nfunction inferXKind(series) {\n let sawAny = false;\n let allNumbers = true;\n let allDates = true;\n for (const s of series) {\n for (const v of (Array.isArray(s.x) ? s.x : [])) {\n if (v === null || v === undefined) continue;\n sawAny = true;\n if (typeof v !== 'number') allNumbers = false;\n if (!(v instanceof Date) && !(typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2}/.test(v))) allDates = false;\n if (!allNumbers && !allDates) return 'category';\n }\n }\n if (!sawAny || allNumbers) return 'number';\n return allDates ? 'date' : 'category';\n}\n\n/** A value as a number, or `null` \u2014 never `NaN`. */\nfunction toNumber(value) {\n if (value === null || value === undefined || value === '') return null;\n const n = Number(value);\n return Number.isFinite(n) ? n : null;\n}\n\n/** A Y bound as the axis reads it: on a log axis Plotly reads `range` in log\u2081\u2080\n * units, and a non-positive bound has no place there at all. */\nfunction axisBound(value, log) {\n const n = toNumber(value);\n if (n === null || !log) return n;\n return n > 0 ? Math.log10(n) : null;\n}\n\nfunction fractionDigits(decimals) {\n const d = Math.max(0, Math.min(20, Number(decimals) || 0));\n return { minimumFractionDigits: d, maximumFractionDigits: d };\n}\n\n/** Seconds as `1d 4h`, `4h 12m`, `12m 30s`, `30s` \u2014 two units, never three. */\nfunction formatDuration(seconds) {\n if (!Number.isFinite(seconds)) return '\u2014';\n const sign = seconds < 0 ? '-' : '';\n let rest = Math.abs(Math.round(seconds));\n const days = Math.floor(rest / 86400); rest -= days * 86400;\n const hours = Math.floor(rest / 3600); rest -= hours * 3600;\n const minutes = Math.floor(rest / 60);\n const secs = rest - minutes * 60;\n if (days) return `${sign}${days}d ${hours}h`;\n if (hours) return `${sign}${hours}h ${minutes}m`;\n if (minutes) return `${sign}${minutes}m ${secs}s`;\n return `${sign}${secs}s`;\n}\n\n/**\n * The KPI's formatter. `currency` has NO default: a symbol nobody chose is a\n * claim about money that may be false. `percent` takes a RATIO (0.42 \u2192 42%).\n */\nfunction formatValue(value, { format = 'number', decimals = null, prefix = '', suffix = '',\n currency = null } = {}) {\n if (value === null || value === undefined || value === '') return '\u2014';\n const n = Number(value);\n const body = (() => {\n switch (format) {\n case 'number':\n if (!Number.isFinite(n)) return String(value);\n return decimals === null || decimals === undefined\n ? n.toLocaleString()\n : n.toLocaleString(undefined, fractionDigits(decimals));\n case 'percent':\n if (!Number.isFinite(n)) return String(value);\n return `${(n * 100).toLocaleString(undefined, fractionDigits(decimals ?? 1))}%`;\n case 'currency':\n if (!Number.isFinite(n)) return String(value);\n if (!currency) return n.toLocaleString(undefined, fractionDigits(decimals ?? 2));\n try {\n return n.toLocaleString(undefined, { style: 'currency', currency, ...fractionDigits(decimals ?? 2) });\n } catch {\n // An unknown code throws a RangeError from inside a render.\n return n.toLocaleString(undefined, fractionDigits(decimals ?? 2));\n }\n case 'duration':\n return formatDuration(n);\n default:\n return String(value);\n }\n })();\n return `${prefix || ''}${body}${suffix || ''}`;\n}\n\nfunction slug(text) {\n return String(text).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'chart';\n}\n", "/**\n * layout_persistence.js \u2014 saved tile layouts, keyed by whatever the app keys them by.\n *\n * Three things used to make this un-shippable, and all three are now injected:\n *\n * 1. It wrote to `localStorage` under 'ecosim.results.layouts' and\n * 'ecosim.results.configs' \u2014 a LIBRARY scribbling on one application's storage\n * keys. The keys are the consumer's now, and EcoAgent passes its existing ones,\n * so not a single saved layout is orphaned.\n *\n * 2. It imported EcoAgent's TemplateRegistry to pick a starting layout. That is a\n * `resolveTemplate` callback now: hand it your context, get a layout back, or\n * return null and get an empty grid.\n *\n * 3. Everything was called `scenarioId`, 85 times. A tile layout is keyed by\n * SOMETHING \u2014 a scenario, a document, a user, a run \u2014 and the library does not\n * get an opinion about which. It is `contextId` now. This is a rename of\n * IDENTIFIERS only: the old name was never a stored string, just a key into the\n * stored object, so no persisted data changes shape.\n *\n * `storage` is any synchronous Storage-shaped object (getItem/setItem/removeItem).\n * It defaults to localStorage because that is what a browser has; it is not the Host,\n * because the Host is async and every caller of this class is not.\n */\n\nconst LAYOUT_VERSION = 3;\n\nconst DEFAULT_LAYOUTS_KEY = 'twm.tiles.layouts';\nconst DEFAULT_CONFIGS_KEY = 'twm.tiles.configs';\n\nexport class LayoutPersistence {\n constructor({\n storage = (typeof localStorage !== 'undefined' ? localStorage : null),\n layoutsKey = DEFAULT_LAYOUTS_KEY,\n configsKey = DEFAULT_CONFIGS_KEY,\n resolveTemplate = null,\n logger = null,\n } = {}) {\n this._cache = null;\n this._storage = storage;\n this._logger = logger;\n this._layoutsKey = layoutsKey;\n this._configsKey = configsKey;\n // (context) => layout | null. No resolver => no starting template.\n this._resolveTemplate = typeof resolveTemplate === 'function' ? resolveTemplate : null;\n }\n\n /**\n * Get layout for a specific context.\n * Falls back to template resolution when no saved layout exists.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} Layout object with tiles array\n */\n getLayout(contextId, context) {\n const all = this._loadAll();\n const layout = all[contextId];\n\n if (layout && layout.version === LAYOUT_VERSION) {\n return layout;\n }\n\n // Resolve a template based on context metadata\n const instantiated = this._resolveTemplate?.(context) ?? null;\n if (instantiated) {\n return {\n tiles: instantiated.tiles,\n version: LAYOUT_VERSION,\n templateId: instantiated.templateId,\n templateModified: false,\n };\n }\n\n // Final fallback: empty layout (should not happen \u2014 resolve always returns a default)\n return { tiles: [], version: LAYOUT_VERSION };\n }\n\n /**\n * Save layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n saveLayout(contextId, layout) {\n const all = this._loadAll();\n\n // Handle both array (from TileGrid.getLayout) and object (with tiles property) formats\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId] = {\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n updatedAt: Date.now(),\n templateId: layout?.templateId || all[contextId]?.templateId || null,\n templateModified: layout?.templateModified ?? true,\n };\n\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Saved layout for context ${contextId}`);\n }\n\n /**\n * Delete layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n */\n deleteLayout(contextId) {\n const all = this._loadAll();\n\n if (all[contextId]) {\n delete all[contextId];\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted layout for context ${contextId}`);\n }\n }\n\n /**\n * Reset a layout by re-resolving the best-matching template.\n *\n * With no `resolveTemplate` supplied, \"reset\" means \"empty grid\" \u2014 which is the\n * honest answer for a library that has no templates. The previous code called\n * `TemplateRegistry.instantiate()` unconditionally and read `.tiles` off the\n * result, so a null resolver here would have been a TypeError.\n *\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} The resolved layout (empty if nothing resolves).\n */\n resetLayout(contextId, context) {\n const instantiated = this._resolveTemplate?.(context) ?? null;\n const layout = {\n tiles: instantiated?.tiles ?? [],\n version: LAYOUT_VERSION,\n templateId: instantiated?.templateId ?? null,\n templateModified: false,\n };\n this.saveLayout(contextId, layout);\n return layout;\n }\n\n /**\n * Check if a context has a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n hasLayout(contextId) {\n const all = this._loadAll();\n return !!all[contextId];\n }\n\n /**\n * Get all context IDs with saved layouts.\n * @returns {Array<string>}\n */\n getAllContextIds() {\n const all = this._loadAll();\n return Object.keys(all);\n }\n\n /**\n * Export all layouts as JSON string.\n * @returns {string}\n */\n exportAll() {\n const all = this._loadAll();\n return JSON.stringify(all, null, 2);\n }\n\n /**\n * Import layouts from JSON string.\n * @param {string} json - JSON string of layouts\n * @param {boolean} [merge=false] - Whether to merge with existing or replace\n */\n importAll(json, merge = false) {\n try {\n const imported = JSON.parse(json);\n\n if (merge) {\n const existing = this._loadAll();\n this._saveAll({ ...existing, ...imported });\n } else {\n this._saveAll(imported);\n }\n\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Imported layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to import layouts:', err);\n }\n }\n\n /**\n * Clear all saved layouts.\n */\n clearAll() {\n try {\n this._storage?.removeItem(this._layoutsKey);\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Cleared all layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to clear layouts:', err);\n }\n }\n\n /**\n * Load all layouts from storage.\n * @returns {Object}\n * @private\n */\n _loadAll() {\n if (this._cache) {\n return this._cache;\n }\n\n try {\n const raw = this._storage?.getItem(this._layoutsKey);\n if (raw) {\n this._cache = JSON.parse(raw);\n return this._cache;\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load layouts:', err);\n }\n\n this._cache = {};\n return this._cache;\n }\n\n /**\n * Save all layouts to storage.\n * @param {Object} data\n * @private\n */\n _saveAll(data) {\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save layouts:', err);\n\n // If quota exceeded, try to clear old entries\n if (err.name === 'QuotaExceededError') {\n this._pruneOldLayouts(data);\n }\n }\n }\n\n /**\n * Remove oldest layouts to free up space.\n * @param {Object} data\n * @private\n */\n _pruneOldLayouts(data) {\n const entries = Object.entries(data);\n\n // Sort by updatedAt, oldest first\n entries.sort((a, b) => (a[1].updatedAt || 0) - (b[1].updatedAt || 0));\n\n // Remove oldest 25%\n const removeCount = Math.ceil(entries.length * 0.25);\n for (let i = 0; i < removeCount; i++) {\n delete data[entries[i][0]];\n }\n\n // Try saving again\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n this._logger?.warn?.('[LayoutPersistence] Pruned old layouts due to quota');\n } catch (err) {\n console.error('[LayoutPersistence] Still cannot save after pruning:', err);\n }\n }\n\n /**\n * Get the template ID associated with a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {string|null} Template ID or null\n */\n getTemplateId(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateId || null;\n }\n\n /**\n * Check if the user has modified the layout since the template was applied.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n isTemplateModified(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateModified ?? false;\n }\n\n // =========================================================================\n // NAMED CONFIGURATION MANAGEMENT\n // =========================================================================\n\n /**\n * Get all saved configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object} { activeId: string, configs: { id: { name, tiles, createdAt } } }\n */\n getConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (contextConfigs && Object.keys(contextConfigs.configs || {}).length > 0) {\n return contextConfigs;\n }\n\n // Return empty structure\n return {\n activeId: null,\n configs: {}\n };\n }\n\n /**\n * Save the current layout as a named configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} name - Configuration name\n * @param {Array|Object} layout - Layout to save\n * @param {Object} [options] - Additional options\n * @param {string} [options.templateId] - Template ID that generated this layout\n * @returns {string} The new configuration ID\n */\n saveConfiguration(contextId, name, layout, options) {\n const all = this._loadConfigs();\n\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n\n // Ensure unique name\n const uniqueName = this._getUniqueName(all[contextId].configs, name);\n\n const configId = `config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId] = {\n name: uniqueName,\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n createdAt: Date.now(),\n templateId: options?.templateId || null,\n };\n\n // Set as active if it's the first one\n if (!all[contextId].activeId) {\n all[contextId].activeId = configId;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Saved configuration \"${uniqueName}\" for context ${contextId}`);\n\n return configId;\n }\n\n /**\n * Generate a unique name by appending (2), (3), etc. if name already exists.\n * @param {Object} configs - Existing configurations object\n * @param {string} name - Desired name\n * @returns {string} Unique name\n * @private\n */\n _getUniqueName(configs, name) {\n if (!configs) return name;\n\n const existingNames = new Set(Object.values(configs).map(c => c.name));\n\n if (!existingNames.has(name)) {\n return name;\n }\n\n // Find next available number\n let counter = 2;\n let candidate = `${name} (${counter})`;\n while (existingNames.has(candidate)) {\n counter++;\n candidate = `${name} (${counter})`;\n }\n\n return candidate;\n }\n\n /**\n * Load a specific configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {Object|null} Configuration layout or null if not found\n */\n loadConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n const config = all[contextId]?.configs?.[configId];\n\n if (config) {\n // Update active config\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n return config;\n }\n\n return null;\n }\n\n /**\n * Delete a saved configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {boolean} True if deleted, false if not found\n */\n deleteConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n delete all[contextId].configs[configId];\n\n // Update active if deleted\n if (all[contextId].activeId === configId) {\n const remaining = Object.keys(all[contextId].configs);\n all[contextId].activeId = remaining.length > 0 ? remaining[0] : null;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted configuration ${configId} for context ${contextId}`);\n\n return true;\n }\n\n /**\n * Update an existing configuration's layout (without creating a new ID).\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {Array|Object} layout - New layout to save\n * @returns {boolean} True if updated, false if not found\n */\n updateConfiguration(contextId, configId, layout) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId].tiles = tilesArray;\n all[contextId].configs[configId].version = LAYOUT_VERSION;\n all[contextId].configs[configId].updatedAt = Date.now();\n\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Update the templateId on an existing configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} templateId - New template ID\n * @returns {boolean} True if updated, false if not found\n */\n updateConfigurationTemplateId(contextId, configId, templateId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n all[contextId].configs[configId].templateId = templateId;\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Rename a configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} newName - New name\n * @returns {string|false} The actual name used (may differ if duplicate), or false if not found\n */\n renameConfiguration(contextId, configId, newName) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n // Get configs excluding the one being renamed for uniqueness check\n const otherConfigs = {};\n Object.entries(all[contextId].configs).forEach(([id, config]) => {\n if (id !== configId) {\n otherConfigs[id] = config;\n }\n });\n\n const uniqueName = this._getUniqueName(otherConfigs, newName);\n all[contextId].configs[configId].name = uniqueName;\n this._saveConfigs(all);\n\n return uniqueName;\n }\n\n /**\n * Get the active configuration for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object|null} { id, name, tiles } or null\n */\n getActiveConfiguration(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.activeId) {\n return null;\n }\n\n const activeConfig = contextConfigs.configs[contextConfigs.activeId];\n if (activeConfig) {\n return {\n id: contextConfigs.activeId,\n ...activeConfig\n };\n }\n\n return null;\n }\n\n /**\n * Set the active configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n */\n setActiveConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (all[contextId]?.configs?.[configId]) {\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n }\n }\n\n /**\n * List all configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Array} Array of { id, name, createdAt, isActive }\n */\n listConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.configs) {\n return [];\n }\n\n return Object.entries(contextConfigs.configs).map(([id, config]) => ({\n id,\n name: config.name,\n createdAt: config.createdAt,\n isActive: id === contextConfigs.activeId\n })).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n }\n\n /**\n * Get the template set fingerprint for a context.\n * Used to detect when templates have changed and configs need regeneration.\n * @param {string} contextId\n * @returns {string|null}\n */\n getTemplateSetId(contextId) {\n const all = this._loadConfigs();\n return all[contextId]?.templateSetId || null;\n }\n\n /**\n * Store the template set fingerprint for a context.\n * @param {string} contextId\n * @param {string} templateSetId\n */\n setTemplateSetId(contextId, templateSetId) {\n const all = this._loadConfigs();\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n all[contextId].templateSetId = templateSetId;\n this._saveConfigs(all);\n }\n\n /**\n * Delete ALL configurations for a context.\n * @param {string} contextId\n */\n clearConfigurations(contextId) {\n const all = this._loadConfigs();\n delete all[contextId];\n this._saveConfigs(all);\n }\n\n /**\n * Load all configurations from storage.\n * @returns {Object}\n * @private\n */\n _loadConfigs() {\n try {\n const raw = this._storage?.getItem(this._configsKey);\n if (raw) {\n return JSON.parse(raw);\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load configurations:', err);\n }\n return {};\n }\n\n /**\n * Save all configurations to storage.\n * @param {Object} data\n * @private\n */\n _saveConfigs(data) {\n try {\n this._storage?.setItem(this._configsKey, JSON.stringify(data));\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save configurations:', err);\n }\n }\n}\n\n// Singleton instance\nlet instance = null;\nlet _options = {};\n\n/**\n * Configure the singleton BEFORE anything reads it. Call once, at boot.\n *\n * The first cut let `getLayoutPersistence(options)` configure it lazily \u2014 whoever\n * called first won. That is a trap with teeth: if ANY code path had reached the\n * store before the dashboard did, the singleton would have been built with the\n * library's generic defaults, and the app would have read\n * 'twm.tiles.layouts' instead of 'ecosim.results.layouts' \u2014 an empty store. Every\n * saved dashboard a user had ever built would have silently vanished, with no\n * error, and no captured view would show it because the pixel gate runs on a\n * fresh template that has no saved layouts to lose.\n *\n * Configure once, at boot, where the ordering is not in question.\n */\nexport function configureLayoutPersistence(options = {}) {\n _options = options;\n instance = null; // rebuild on next get\n}\n\n/** @returns {LayoutPersistence} */\nexport function getLayoutPersistence() {\n if (!instance) {\n instance = new LayoutPersistence(_options);\n }\n return instance;\n}\n\nexport default LayoutPersistence;\n", "/**\n * list_tiles.js \u2014 a LIST tile and a PEOPLE tile for a `TileGrid` (0.16.1).\n *\n * Both are rows you hand over through `setData()`, the way the chart tile takes\n * series: which records are in the list, how they sort and what a row says is\n * the embedder's job, because only the embedder knows what a record is. What a\n * tile here owns is everything a list on a board needs and every embedder would\n * otherwise write again: the count, the empty line, the \"open all of these\"\n * button, a click, the keyboard, and a right-click menu per row.\n *\n * import { registerListTiles } from '@flexdesk/tiles';\n * registerListTiles(); // idempotent; nothing registers at import\n * const tile = grid.addTile('flexdesk.list', {x: 0, y: 0, w: 6, h: 4},\n * { title: 'Overdue', empty_text: 'Nothing is late.' });\n * tile.onRowActivate = ({ row, event }) => open(row.key, event.ctrlKey);\n * tile.rowMenu = ({ row }) => [{ label: 'Open', icon: 'open_in_new', action: 'open' }];\n * tile.onRowMenuAction = ({ action, row }) => { \u2026 };\n * tile.setData({\n * rows: [{ key: '7', icon: 'task', lead: 'TASK-0007', title: 'Sign-off',\n * cells: [{ text: 'priya' }, { text: '9 days late', tone: 'danger' }] }],\n * total: 12, // \"7 of 12\" when only 7 are handed over\n * action: { label: 'Open as a list' }, // the button in the bar; see onAction\n * });\n *\n * \u2550\u2550 THE DATA \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 * list { rows: [Row], total?, note?, empty?, action?: {label, icon?} } (an array is {rows})\n * Row = { key, title, icon?, iconTitle?, lead?, className?, tip?,\n * cells?: [{ text, title?, tone?, icon?, className? }] }\n * people { people: [Person], total?, note?, empty?, action? } (an array is {people})\n * Person = { key, name, icon?, muted?, count, countLabel?, title?,\n * pills?: [{ text, tone?, title? }] }\n *\n * `tone` is one of `danger`, `warning`, `ok`, `muted` and only picks a colour;\n * the text says the same thing, because colour alone does not survive a\n * monochrome display. `className` is the embedder's own class, added as it is,\n * so a status pill can keep the app's look.\n *\n * AN EMPTY LIST IS NOT THE EMPTY STATE. `{rows: []}` keeps the bar (count 0,\n * the button) and says `empty` (or `config.empty_text`) where the rows would be:\n * \"nothing is late\" is the most useful thing a list of late work can say, and a\n * tile that shows a grey inbox icon instead cannot say it. `setData(null)` is\n * the empty state; `showEmpty(message)` is how an embedder says \"not set up\".\n *\n * \u2550\u2550 INPUT \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 * A row is `role=\"button\"` with a tab stop. Click, Enter and Space call\n * `onRowActivate({row, event, tile})` with the event, so the modifier keys\n * decide how it opens. Up and Down move between rows, Home and End to the ends.\n * Right-click, the context-menu key and Shift+F10 open the row's menu:\n * `rowMenu({row, event, tile})` answers the items (`showContextMenu`'s; none or\n * `[]` means no menu, and the browser's own is left alone) and the choice goes\n * to `onRowMenuAction({action, row, tile})`. The bar's button calls\n * `onAction({tile, event})`. Every hook can also be passed to the constructor.\n * A row carries `data-row-key`, so an embedder can find it for its own\n * listeners (a drag source, say); `rowsDraggable` makes rows `draggable`.\n *\n * The header reads `config.title`, else the type's title; the count is in the\n * bar, not the header, so a title the embedder sets is never rewritten.\n */\n\nimport { TileBase } from './tile_base.js';\nimport { registerWidget, getWidget } from './tile_registry.js';\nimport { showContextMenu } from '../ui/components/context_menu.js';\n\nconst TONES = new Set(['danger', 'warning', 'ok', 'muted']);\n\n/** `{items, total, note, empty, action}` from what `setData` was handed under\n * `key` (`rows` or `people`), or null when there is nothing at all. */\nfunction normalize(data, key) {\n if (data == null) return null;\n const d = Array.isArray(data) ? { [key]: data } : data;\n if (typeof d !== 'object' || !Array.isArray(d[key])) return null;\n const items = d[key].filter((r) => r && typeof r === 'object' && r.key != null);\n const total = Number.isFinite(Number(d.total)) && d.total !== null && d.total !== '' ? Number(d.total) : items.length;\n return {\n items,\n total: Math.max(total, items.length),\n note: typeof d.note === 'string' ? d.note : '',\n empty: typeof d.empty === 'string' ? d.empty : '',\n action: d.action && typeof d.action === 'object' && d.action.label ? d.action : null,\n };\n}\n\n/** Exported for tests and for an embedder that wants to know what the tile will make of its data. */\nexport const normalizeListData = (data) => normalize(data, 'rows');\nexport const normalizePeopleData = (data) => normalize(data, 'people');\n\nfunction el(tag, cls, text) {\n const e = document.createElement(tag);\n if (cls) e.className = cls;\n if (text != null) e.textContent = String(text);\n return e;\n}\n\nfunction glyph(name, cls = '') {\n const g = el('span', `material-symbols-outlined${cls ? ` ${cls}` : ''}`, name);\n g.setAttribute('aria-hidden', 'true');\n return g;\n}\n\nconst toneClass = (base, tone) => (TONES.has(tone) ? ` ${base}--${tone}` : '');\n\n/**\n * The rows, the bar and the input, shared by both tiles. A subclass says what\n * its items are called in the data (`_KEY`) and draws one (`_renderItem`).\n * @abstract\n */\nclass RowsTile extends TileBase {\n static _KEY = 'rows';\n\n constructor(options = {}) {\n super(options);\n this.onRowActivate = typeof options.onRowActivate === 'function' ? options.onRowActivate : null;\n this.rowMenu = typeof options.rowMenu === 'function' ? options.rowMenu : null;\n this.onRowMenuAction = typeof options.onRowMenuAction === 'function' ? options.onRowMenuAction : null;\n this.onAction = typeof options.onAction === 'function' ? options.onAction : null;\n this.rowsDraggable = options.rowsDraggable === true;\n this._items = new Map(); // key \u2192 the item drawn for it\n this._onClick = (e) => this._click(e);\n this._onKey = (e) => this._key(e);\n this._onMenu = (e) => this._menu(e);\n }\n\n /** Pure and static-only \u2014 it runs inside `TileBase`'s constructor. */\n getDefaultConfig() {\n return { title: '', empty_text: '', max_rows: 0 };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { name: 'title', type: 'text', label: 'Tile title' },\n { name: 'empty_text', type: 'text', label: 'When there is nothing',\n help: 'What the tile says when the list is empty, e.g. \"Nothing is late.\"' },\n { name: 'max_rows', type: 'number', label: 'Rows at most', min: 0,\n help: '0 shows them all; the tile scrolls.' },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n const c = this.contentElement;\n if (!c) return;\n // On the content element, which outlives every render (they replace\n // its children, never it), so one set of listeners serves them all.\n c.addEventListener('click', this._onClick);\n c.addEventListener('keydown', this._onKey);\n c.addEventListener('contextmenu', this._onMenu);\n }\n\n /** `null` is \"the grid has no data\" \u2014 see `ChartTile.update`. */\n update(data, config) {\n if (this._disposed) return;\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n }\n\n /** Hand this tile its rows; null is the empty state. */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n /** The item drawn under `key`, or null. */\n itemFor(key) { return this._items.get(String(key)) ?? null; }\n\n /** The element of the item drawn under `key`, or null. */\n rowElement(key) {\n const want = String(key);\n return [...(this.contentElement?.querySelectorAll('[data-row-key]') || [])]\n .find((r) => r.dataset.rowKey === want) || null;\n }\n\n render(data) {\n const content = this.contentElement;\n if (!content) return;\n const norm = normalize(data, this.constructor._KEY);\n this._items.clear();\n if (!norm) { this.showEmpty('Nothing to show.'); return; }\n\n const max = Math.max(0, Math.floor(Number(this.config.max_rows) || 0));\n const shown = max ? norm.items.slice(0, max) : norm.items;\n const box = el('div', `fd-list-tile fd-list-tile--${this.constructor._KEY}`);\n\n const bar = el('div', 'fd-list-tile__bar');\n const count = el('span', 'fd-list-tile__count',\n shown.length < norm.total ? `${shown.length} of ${norm.total}` : String(norm.total));\n count.title = `${norm.total} in all`;\n bar.append(count, el('span', 'fd-list-tile__spacer'));\n if (norm.action) {\n const b = el('button', 'fd-list-tile__action');\n b.type = 'button';\n b.dataset.listAction = 'action';\n if (norm.action.icon) b.append(glyph(norm.action.icon));\n b.append(el('span', null, norm.action.label));\n bar.append(b);\n }\n box.append(bar);\n\n const list = el('div', 'fd-list-tile__rows');\n list.setAttribute('role', 'list');\n if (!shown.length) {\n list.append(el('div', 'fd-list-tile__empty', norm.empty || this.config.empty_text || 'Nothing here.'));\n }\n for (const item of shown) {\n const key = String(item.key);\n if (this._items.has(key)) continue; // one row per key: a second would be unreachable\n this._items.set(key, item);\n const row = this._renderItem(item);\n row.classList.add('fd-list-tile__row');\n row.dataset.rowKey = key;\n row.setAttribute('role', 'button');\n row.tabIndex = 0;\n if (this.rowsDraggable) row.draggable = true;\n const wrap = el('div', 'fd-list-tile__item');\n wrap.setAttribute('role', 'listitem');\n wrap.append(row);\n list.append(wrap);\n }\n box.append(list);\n if (norm.note) {\n const note = el('div', 'fd-list-tile__note', norm.note);\n note.setAttribute('role', 'note');\n note.title = norm.note;\n box.append(note);\n }\n content.replaceChildren(box);\n }\n\n /** One item's row element. @abstract */\n _renderItem(_item) { return el('div'); }\n\n // \u2500\u2500 input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _rowOf(target) {\n const row = target?.closest?.('[data-row-key]');\n return row && this.contentElement?.contains(row) ? row : null;\n }\n\n _click(e) {\n if (e.target?.closest?.('[data-list-action]')) {\n this._call(this.onAction, { tile: this, event: e });\n return;\n }\n const row = this._rowOf(e.target);\n if (row) this._activate(row, e);\n }\n\n _activate(rowEl, event) {\n const row = this.itemFor(rowEl.dataset.rowKey);\n if (row) this._call(this.onRowActivate, { row, event, tile: this });\n }\n\n _key(e) {\n const rowEl = this._rowOf(e.target);\n if (!rowEl) return;\n if (e.key === 'ContextMenu' || (e.key === 'F10' && e.shiftKey)) {\n const r = rowEl.getBoundingClientRect();\n if (this._openMenu(rowEl, e, r.left + 16, r.bottom)) e.preventDefault();\n return;\n }\n if ((e.key === 'Enter' || e.key === ' ') && !e.altKey) {\n e.preventDefault();\n this._activate(rowEl, e);\n return;\n }\n const rows = [...this.contentElement.querySelectorAll('[data-row-key]')];\n const i = rows.indexOf(rowEl);\n const to = { ArrowDown: i + 1, ArrowUp: i - 1, Home: 0, End: rows.length - 1 }[e.key];\n if (to === undefined || !rows[to]) return;\n e.preventDefault();\n rows[to].focus();\n }\n\n _menu(e) {\n const rowEl = this._rowOf(e.target);\n if (rowEl && this._openMenu(rowEl, e, e.clientX, e.clientY)) e.preventDefault();\n }\n\n /** Show the row's menu, if it has one. \u2192 whether it did. */\n _openMenu(rowEl, event, x, y) {\n const row = this.itemFor(rowEl.dataset.rowKey);\n if (!row || typeof this.rowMenu !== 'function') return false;\n let items = null;\n try { items = this.rowMenu({ row, event, tile: this }); }\n catch (err) { console.error(`[${this.constructor.name}] rowMenu threw:`, err); return false; }\n if (!Array.isArray(items) || !items.length) return false;\n showContextMenu(x, y, items, (action) => this._call(this.onRowMenuAction, { action, row, tile: this }));\n return true;\n }\n\n /** A hook, called so that one that throws is reported and the tile goes on. */\n _call(fn, arg) {\n if (typeof fn !== 'function') return;\n try { fn(arg); } catch (err) { console.error(`[${this.constructor.name}] a callback threw:`, err); }\n }\n\n dispose() {\n const c = this.contentElement;\n if (c) {\n c.removeEventListener('click', this._onClick);\n c.removeEventListener('keydown', this._onKey);\n c.removeEventListener('contextmenu', this._onMenu);\n }\n this._items.clear();\n super.dispose();\n }\n}\n\n/**\n * A LIST OF RECORDS: an icon, a lead (a reference, say), the title, and cells.\n * See the header for the data and the input.\n */\nexport class ListTile extends RowsTile {\n static TYPE = 'flexdesk.list';\n static TITLE = 'List';\n static ICON = 'list';\n static DESCRIPTION = 'Rows you supply, with a count, a click and a right-click menu per row.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 2, maxW: 12, maxH: 12 };\n static _KEY = 'rows';\n\n _renderItem(r) {\n const row = el('div', r.className ? String(r.className) : null);\n if (r.icon) {\n const g = glyph(r.icon, 'fd-list-tile__icon');\n if (r.iconTitle) { g.title = r.iconTitle; g.removeAttribute('aria-hidden'); }\n row.append(g);\n }\n if (r.lead != null && r.lead !== '') row.append(el('span', 'fd-list-tile__lead', r.lead));\n const title = el('span', 'fd-list-tile__title', r.title ?? '');\n title.title = r.tip || String(r.title ?? '');\n row.append(title);\n for (const c of Array.isArray(r.cells) ? r.cells : []) {\n if (!c) continue;\n const cell = el('span', `fd-list-tile__cell${toneClass('fd-list-tile__cell', c.tone)}${c.className ? ` ${c.className}` : ''}`);\n if (c.icon) cell.append(glyph(c.icon));\n if (c.text != null && c.text !== '') cell.append(document.createTextNode(String(c.text)));\n if (c.title) cell.title = c.title;\n row.append(cell);\n }\n return row;\n }\n}\n\n/**\n * WHO HAS WHAT: one row per person, with a count and pills. The order is the\n * embedder's (the list is read top-down and stopped at, so the order should BE\n * the priority); `groupByPerson` is a starting point for building it.\n */\nexport class PeopleTile extends RowsTile {\n static TYPE = 'flexdesk.people';\n static TITLE = 'People';\n static ICON = 'groups';\n static DESCRIPTION = 'One row per person, with how much is on them.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 2, maxW: 12, maxH: 12 };\n static _KEY = 'people';\n\n getDefaultConfig() {\n return { ...super.getDefaultConfig(), count_label: 'open' };\n }\n\n getConfigSchema() {\n const { fields } = super.getConfigSchema();\n return { fields: [...fields, { name: 'count_label', type: 'text', label: 'Count reads',\n help: 'After each person\\'s number, e.g. \"open\" for \"3 open\".' }] };\n }\n\n _renderItem(p) {\n const row = el('div', 'fd-people-tile__row');\n row.append(glyph(p.icon || (p.muted ? 'person_off' : 'person'), 'fd-list-tile__icon'));\n row.append(el('span', `fd-people-tile__name${p.muted ? ' fd-people-tile__name--muted' : ''}`, p.name ?? p.key));\n const pills = el('span', 'fd-people-tile__pills');\n for (const pill of Array.isArray(p.pills) ? p.pills : []) {\n if (!pill?.text) continue;\n const s = el('span', `fd-people-tile__pill${toneClass('fd-people-tile__pill', pill.tone)}`, pill.text);\n if (pill.title) s.title = pill.title;\n pills.append(s);\n }\n row.append(pills);\n const label = p.countLabel ?? this.config.count_label ?? '';\n row.append(el('span', 'fd-people-tile__count', `${Number(p.count) || 0}${label ? ` ${label}` : ''}`));\n if (p.title) row.title = p.title;\n return row;\n }\n}\n\n/**\n * Items grouped by person: `[{key, items}]`, most items first, then by key, the\n * nobody group (key `''`) last among equals. `personOf(item)` answers the\n * person's key, or a falsy value for nobody.\n */\nexport function groupByPerson(items, personOf) {\n const by = new Map();\n for (const item of Array.isArray(items) ? items : []) {\n const who = String(personOf(item) || '');\n if (!by.has(who)) by.set(who, { key: who, items: [] });\n by.get(who).items.push(item);\n }\n return [...by.values()].sort((a, b) => b.items.length - a.items.length\n || (a.key === '') - (b.key === '') || a.key.localeCompare(b.key));\n}\n\n/**\n * Register both tiles. Idempotent, and nothing registers at import time \u2014 see\n * `registerChartTiles`.\n */\nexport function registerListTiles() {\n for (const Tile of [ListTile, PeopleTile]) {\n if (getWidget(Tile.TYPE) !== Tile) registerWidget(Tile);\n }\n}\n\n/** The header shows `config.title`, else the type's own title. */\nfunction applyTitle(tile) {\n tile.setTitle(tile.config.title || tile.constructor.TITLE);\n}\n", "/**\n * scope_picker.js \u2014 ONE FILTER FOR THE WHOLE BOARD (0.16.1).\n *\n * A row of buttons, one per scope (\"Everyone\", \"Assigned by me\", \u2026), exactly\n * one of them pressed. It is the control half of a dashboard-level filter; the\n * other half is `TileGrid.setScope()`, which hands the value to every tile\n * (`tile.scope`, `tile.onScopeChange`) and to the grid's `onScopeChange`:\n *\n * const picker = createScopePicker({\n * options: [{ value: 'all', label: 'Everyone' },\n * { value: 'mine', label: 'Mine', hint: 'only what is on me' }],\n * value: 'all',\n * onChange: (value) => grid.setScope(value),\n * });\n * header.append(picker.element);\n *\n * What a scope MEANS is the embedder's: the grid only carries the value, and a\n * tile that knows nothing about scopes is unaffected by one.\n *\n * Each button has `aria-pressed`, the group a label. Left and Right move the\n * focus along the row and Enter or Space presses, as on any button; a click on\n * the button already pressed changes nothing and calls nothing.\n */\n\n/**\n * @param {Object} o\n * @param {Array<{value: string, label: string, hint?: string}>} o.options\n * @param {string} [o.value] - The pressed one; the first option when absent or unknown.\n * @param {string} [o.label='Scope'] - The group's accessible name.\n * @param {(value: string) => void} [o.onChange] - After the user presses another one.\n * @returns {{element: HTMLElement, readonly value: string, setValue: (v: string) => void, dispose: () => void}}\n */\nexport function createScopePicker({ options = [], value, label = 'Scope', onChange } = {}) {\n const opts = options.filter((o) => o && o.value != null).map((o) => ({ ...o, value: String(o.value) }));\n const known = (v) => opts.some((o) => o.value === String(v));\n let current = known(value) ? String(value) : opts[0]?.value ?? '';\n\n const element = document.createElement('span');\n element.className = 'fd-scope-picker';\n element.setAttribute('role', 'group');\n element.setAttribute('aria-label', label);\n\n const buttons = opts.map((o) => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'fd-scope-picker__btn';\n b.dataset.scope = o.value;\n b.textContent = o.label ?? o.value;\n if (o.hint) b.title = o.hint;\n element.append(b);\n return b;\n });\n\n const paint = () => {\n for (const b of buttons) {\n const on = b.dataset.scope === current;\n b.classList.toggle('fd-scope-picker__btn--on', on);\n b.setAttribute('aria-pressed', String(on));\n }\n };\n paint();\n\n const onClick = (e) => {\n const b = e.target?.closest?.('[data-scope]');\n if (!b || !element.contains(b) || b.dataset.scope === current) return;\n current = b.dataset.scope;\n paint();\n try { onChange?.(current); } catch (err) { console.error('[ScopePicker] onChange threw:', err); }\n };\n const onKey = (e) => {\n const i = buttons.indexOf(e.target);\n if (i < 0) return;\n const to = { ArrowRight: i + 1, ArrowLeft: i - 1, Home: 0, End: buttons.length - 1 }[e.key];\n if (to === undefined || !buttons[to]) return;\n e.preventDefault();\n buttons[to].focus();\n };\n element.addEventListener('click', onClick);\n element.addEventListener('keydown', onKey);\n\n return {\n element,\n get value() { return current; },\n /** Press `v` without calling `onChange` (a value restored from elsewhere). */\n setValue(v) {\n if (!known(v)) return;\n current = String(v);\n paint();\n },\n dispose() {\n element.removeEventListener('click', onClick);\n element.removeEventListener('keydown', onKey);\n element.remove();\n },\n };\n}\n", "/**\n * tile_grid.js\n *\n * Core draggable tile grid system.\n * Manages a 12-column CSS grid with drag-and-drop repositioning and resize functionality.\n */\n\nimport { createWidget, getWidgetCatalog } from './tile_registry.js';\nimport { ActionDropdown } from '../ui/components/action_dropdown.js';\n\nexport class TileGrid {\n /**\n * @param {Object} options\n * @param {HTMLElement} options.container - Container element for the grid\n * @param {number} [options.columns=12] - Number of grid columns\n * @param {number} [options.rowHeight=80] - Height of each grid row in pixels\n * @param {number} [options.gap=16] - Gap between tiles in pixels\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {boolean} [options.showToolbar=true] - Whether to show built-in toolbar\n * @param {Function} [options.onLayoutChange] - Callback when layout changes\n * @param {Function} [options.onAddWidget] - Callback for add widget action\n * @param {Function} [options.onResetLayout] - Callback for reset layout action\n * @param {Function} [options.onExport] - Callback for export action\n * @param {{resolve: Function}} [options.dataSource] - Per-tile data provider,\n * handed to every tile. With none, the grid is the broadcast-only grid\n * it has always been and no tile is ever asked to load anything.\n * @param {*} [options.scope=null] - The board's scope, a filter every tile\n * follows (0.16.1); see `setScope`.\n * @param {Function} [options.onScopeChange] - `(scope)` after `setScope` changed it.\n */\n constructor({ container, columns = 12, rowHeight = 80, gap = 16, eventBus = null,\n showToolbar = true, readonly = false, onLayoutChange, onBeforeLayoutChange,\n onAddWidget, onResetLayout, onExport,\n // Handed down to every tile. TileBase used to import appHost() from\n // ui/js/ecoagent/ to back Expand -> Export CSV/PNG; a grid that has\n // no host simply gets the Blob-download fallback the host contract\n // promises. It is not an error to have none.\n host = null, stateGuard = null,\n // Injected, never constructed here: the grid does not know what\n // a binding is, only that a tile may have somewhere to ask.\n dataSource = null, scope = null, onScopeChange = null }) {\n this.host = host;\n this.scope = scope;\n this._onScopeChangeCallback = onScopeChange;\n this.stateGuard = stateGuard;\n this.dataSource = dataSource;\n this.container = container;\n this.columns = columns;\n this.rowHeight = rowHeight;\n this.gap = gap;\n this.eventBus = eventBus;\n this.showToolbar = showToolbar;\n this.readonly = readonly;\n this._onLayoutChangeCallback = onLayoutChange;\n this._onBeforeLayoutChangeCallback = onBeforeLayoutChange;\n this._onAddWidgetCallback = onAddWidget;\n this._onResetLayoutCallback = onResetLayout;\n this._onExportCallback = onExport;\n\n /** @type {Map<string, import('./tile_base.js').TileBase>} */\n this.tiles = new Map();\n\n /** @type {Array<{id: string, x: number, y: number, w: number, h: number}>} */\n this.layout = [];\n\n /** @type {Set<string>|null} IDs of documentation cells (for \"Show in Documentation\" visibility) */\n this.documentationCellIds = null;\n\n this.gridElement = null;\n this.data = null;\n this.fullData = null;\n\n // Drag state\n this._dragState = null;\n this._resizeState = null;\n this._ghostElement = null;\n\n // Bound handlers for cleanup\n this._boundOnPointerMove = this._onPointerMove.bind(this);\n this._boundOnPointerUp = this._onPointerUp.bind(this);\n\n this._init();\n }\n\n /**\n * Initialize the grid container.\n * @private\n */\n _init() {\n // Create grid element\n this.gridElement = document.createElement('div');\n this.gridElement.className = 'tile-grid';\n this.gridElement.style.setProperty('--grid-columns', this.columns);\n this.gridElement.style.setProperty('--grid-row-height', `${this.rowHeight}px`);\n this.gridElement.style.setProperty('--grid-gap', `${this.gap}px`);\n\n // Add grid to container\n this.container.innerHTML = '';\n this.container.appendChild(this.gridElement);\n\n // Add toolbar (can be disabled for external toolbar)\n if (this.showToolbar) {\n this._buildToolbar();\n }\n\n // Listen for tile events\n this.gridElement.addEventListener('tile:config-request', this._onTileConfigRequest.bind(this));\n this.gridElement.addEventListener('tile:remove-request', this._onTileRemoveRequest.bind(this));\n\n // Global pointer events for drag/resize\n document.addEventListener('pointermove', this._boundOnPointerMove);\n document.addEventListener('pointerup', this._boundOnPointerUp);\n }\n\n /**\n * Build the dashboard bottom toolbar with add widget dropdown.\n * @private\n */\n _buildToolbar() {\n const toolbar = document.createElement('div');\n toolbar.className = 'tile-grid-toolbar tile-grid-toolbar--bottom';\n this._toolbarElement = toolbar;\n\n toolbar.innerHTML = `\n <div class=\"toolbar-group toolbar-group--main\">\n <div class=\"add-widget-container\">\n <button class=\"toolbar-btn add-widget-btn twm-has-tooltip\" data-tooltip=\"Add widget\">\n <span class=\"material-symbols-outlined\">add</span>\n <span>Add Widget</span>\n <span class=\"material-symbols-outlined dropdown-arrow\">expand_less</span>\n </button>\n </div>\n <button class=\"toolbar-btn reset-layout-btn twm-has-tooltip\" data-tooltip=\"Reset to default layout\">\n <span class=\"material-symbols-outlined\">restart_alt</span>\n <span class=\"btn-text\">Reset</span>\n </button>\n <button class=\"toolbar-btn export-btn twm-has-tooltip\" data-tooltip=\"Export report\">\n <span class=\"material-symbols-outlined\">download</span>\n <span class=\"btn-text\">Export</span>\n </button>\n </div>\n `;\n\n // Create add-widget dropdown via ActionDropdown\n const addBtn = toolbar.querySelector('.add-widget-btn');\n const catalog = getWidgetCatalog();\n this._addWidgetDropdown = new ActionDropdown({\n trigger: addBtn,\n options: catalog.map(w => ({ type: w.type, label: w.title, icon: w.icon, description: w.description })),\n onSelect: (opt) => this._addWidgetFromDropdown(opt.type),\n className: 'add-widget-dropdown-menu'\n });\n\n toolbar.querySelector('.reset-layout-btn')?.addEventListener('click', () => this._resetLayout());\n toolbar.querySelector('.export-btn')?.addEventListener('click', () => this._exportReport());\n\n // Insert after grid element (at bottom)\n this.container.appendChild(toolbar);\n }\n\n /**\n * Add a widget from the dropdown selection.\n * @param {string} type - Widget type\n * @private\n */\n _addWidgetFromDropdown(type) {\n import('./tile_registry.js').then(({ getWidget }) => {\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n });\n }\n\n /**\n * Add a tile to the grid.\n * @param {string} type - Widget type\n * @param {Object} position - Grid position {x, y, w, h}\n * @param {Object} [config] - Widget configuration\n * @param {string} [id] - Optional tile ID (generated if not provided)\n * @returns {import('./tile_base.js').TileBase | null} The created tile or null\n */\n addTile(type, position, config = {}, id = null) {\n const tileId = id || `tile-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n\n const tile = createWidget(type, {\n id: tileId,\n grid: this,\n eventBus: this.eventBus,\n config,\n readonly: this.readonly,\n host: this.host,\n stateGuard: this.stateGuard,\n dataSource: this.dataSource,\n });\n\n if (!tile) return null;\n // Before mount, so a tile's first render and first load already follow it.\n tile.scope = this.scope;\n\n // Add to layout\n const layoutEntry = {\n id: tileId,\n type,\n x: position.x,\n y: position.y,\n w: position.w,\n h: position.h,\n config\n };\n this.layout.push(layoutEntry);\n\n // Store tile instance\n this.tiles.set(tileId, tile);\n\n // Mount to grid\n tile.mount(this.gridElement);\n this._applyTilePosition(tile, layoutEntry);\n\n // Setup drag handles\n this._setupTileDragHandlers(tile);\n\n // Render with current data if available\n if (this.data) {\n tile.fullData = this.fullData;\n tile.update(this.data);\n } else if (this.dataSource) {\n // A tile that fetches its own rows is never handed any, so the branch\n // above cannot fire for it and it would mount empty and stay empty\n // until something else happened to it. NOT awaited: `setLayout` calls\n // `addTile` in a loop, and awaiting here would serialise a board into\n // one request per tile in sequence \u2014 the opposite of what a batching\n // data source exists to do.\n tile.loadData?.();\n }\n\n // Emit layout changed\n this._emitLayoutChanged();\n\n return tile;\n }\n\n /**\n * Remove a tile from the grid.\n * @param {string} tileId - Tile ID to remove\n */\n removeTile(tileId) {\n const tile = this.tiles.get(tileId);\n if (!tile) return;\n\n tile.dispose();\n this.tiles.delete(tileId);\n\n // Remove from layout\n this.layout = this.layout.filter(l => l.id !== tileId);\n\n this._emitLayoutChanged();\n }\n\n /**\n * Update all tiles with new data.\n * @param {Object} data - Analytics data\n */\n setData(data) {\n this.data = data;\n this.tiles.forEach(tile => {\n tile.fullData = this.fullData;\n tile.update(data);\n });\n }\n\n /**\n * Ask every self-fetching tile to load again, bypassing whatever the data\n * source has cached.\n *\n * The counterpart of `setData` for the pull model: `setData` is how a caller\n * with one dataset for the whole board pushes it, and this is how a caller\n * whose tiles each own a query says \"that underlying data changed\". Passing\n * `ids` narrows it to the tiles a change actually touched, which is what an\n * invalidation carrying a table id can work out and a broadcast cannot.\n *\n * Not awaited and returns nothing: the tiles render themselves as their own\n * requests land, and a caller that waited for all of them would be waiting on\n * the slowest tile to show the fastest one.\n *\n * @param {string[]|Set<string>|null} [ids] - Tile ids, or null for all.\n */\n reloadAll(ids = null) {\n if (!this.dataSource) return;\n const wanted = ids ? new Set(ids) : null;\n this.tiles.forEach((tile, tileId) => {\n if (wanted && !wanted.has(tileId)) return;\n tile.loadData?.({ force: true });\n });\n }\n\n /**\n * THE BOARD'S SCOPE: one filter every tile follows (\"Everyone\", \"Assigned\n * by me\", \u2026), set from a `createScopePicker` or from anything else.\n *\n * The grid only carries the value; what it means is the embedder's. Every\n * tile gets it as `tile.scope` and through `tile.onScopeChange(scope)`, the\n * grid's `onScopeChange(scope)` is called, and a grid with a data source\n * reloads its tiles, since their rows depend on it. The scope is not part\n * of the layout: it is how the board is being looked at, not what is on it.\n *\n * @param {*} scope - Compared by JSON: setting the same scope again does nothing.\n * @returns {boolean} whether it changed\n */\n setScope(scope) {\n if (JSON.stringify(scope ?? null) === JSON.stringify(this.scope ?? null)) return false;\n this.scope = scope ?? null;\n this.tiles.forEach((tile) => {\n tile.scope = this.scope;\n try { tile.onScopeChange?.(this.scope); }\n catch (err) { console.error('[TileGrid] a tile\\'s onScopeChange threw:', err); }\n });\n try { this._onScopeChangeCallback?.(this.scope); }\n catch (err) { console.error('[TileGrid] onScopeChange threw:', err); }\n this.eventBus?.emit?.('grid:scope-changed', { scope: this.scope });\n if (this.dataSource) this.reloadAll();\n return true;\n }\n\n /**\n * Get current layout.\n * @returns {Array} Layout array\n */\n getLayout() {\n return this.layout.map(l => ({\n id: l.id,\n type: l.type,\n x: l.x,\n y: l.y,\n w: l.w,\n h: l.h,\n config: this.tiles.get(l.id)?.config || l.config\n }));\n }\n\n /**\n * Set layout and rebuild tiles.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n setLayout(layout) {\n // Clear existing tiles\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n // Clear grid content (keep toolbar)\n this.gridElement.innerHTML = '';\n\n // Handle both array and object with tiles property\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n // Rebuild from layout\n tilesArray.forEach(item => {\n this.addTile(item.type, {\n x: item.x,\n y: item.y,\n w: item.w,\n h: item.h\n }, item.config, item.id);\n });\n }\n\n /**\n * Apply CSS grid position to a tile element.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {{x: number, y: number, w: number, h: number}} position\n * @private\n */\n _applyTilePosition(tile, position) {\n if (!tile.element) return;\n\n tile.element.style.gridColumn = `${position.x + 1} / span ${position.w}`;\n tile.element.style.gridRow = `${position.y + 1} / span ${position.h}`;\n }\n\n /**\n * Setup drag and resize handlers for a tile.\n * @param {import('./tile_base.js').TileBase} tile\n * @private\n */\n _setupTileDragHandlers(tile) {\n if (!tile.element || this.readonly) return;\n\n const dragHandle = tile.element.querySelector('.tile-drag-handle');\n const resizeHandle = tile.element.querySelector('.tile-resize-handle');\n\n // Drag handle\n if (dragHandle) {\n dragHandle.addEventListener('pointerdown', (e) => this._onDragStart(tile, e));\n }\n\n // Resize handle\n if (resizeHandle) {\n resizeHandle.addEventListener('pointerdown', (e) => this._onResizeStart(tile, e));\n }\n }\n\n /**\n * Handle drag start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onDragStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = tile.element.getBoundingClientRect();\n const gridRect = this.gridElement.getBoundingClientRect();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._dragState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startGridX: layoutItem.x,\n startGridY: layoutItem.y,\n tileRect: rect,\n gridRect,\n w: layoutItem.w,\n h: layoutItem.h\n };\n\n tile.element.classList.add('dragging');\n\n // Create ghost element\n this._createGhost(rect);\n }\n\n /**\n * Handle resize start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onResizeStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n const gridRect = this.gridElement.getBoundingClientRect();\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._resizeState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startW: layoutItem.w,\n startH: layoutItem.h,\n gridRect,\n cellWidth,\n x: layoutItem.x,\n y: layoutItem.y\n };\n\n tile.element.classList.add('resizing');\n }\n\n /**\n * Handle pointer move (drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerMove(e) {\n if (this._dragState) {\n this._onDragMove(e);\n } else if (this._resizeState) {\n this._onResizeMove(e);\n }\n }\n\n /**\n * Handle drag move.\n * @param {PointerEvent} e\n * @private\n */\n _onDragMove(e) {\n const state = this._dragState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate cell dimensions\n const gridRect = state.gridRect;\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n const cellHeight = this.rowHeight;\n\n // Calculate new grid position\n const deltaGridX = Math.round(dx / (cellWidth + this.gap));\n const deltaGridY = Math.round(dy / (cellHeight + this.gap));\n\n let newX = state.startGridX + deltaGridX;\n let newY = state.startGridY + deltaGridY;\n\n // Clamp to grid bounds\n newX = Math.max(0, Math.min(newX, this.columns - state.w));\n newY = Math.max(0, newY);\n\n // Update ghost position\n if (this._ghostElement) {\n const ghostLeft = newX * (cellWidth + this.gap);\n const ghostTop = newY * (cellHeight + this.gap);\n this._ghostElement.style.transform = `translate(${ghostLeft}px, ${ghostTop}px)`;\n this._ghostElement.style.width = `${state.w * cellWidth + (state.w - 1) * this.gap}px`;\n this._ghostElement.style.height = `${state.h * cellHeight + (state.h - 1) * this.gap}px`;\n }\n\n // Store pending position\n state.pendingX = newX;\n state.pendingY = newY;\n }\n\n /**\n * Handle resize move.\n * @param {PointerEvent} e\n * @private\n */\n _onResizeMove(e) {\n const state = this._resizeState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate new size in grid cells\n const deltaW = Math.round(dx / (state.cellWidth + this.gap));\n const deltaH = Math.round(dy / (this.rowHeight + this.gap));\n\n let newW = state.startW + deltaW;\n let newH = state.startH + deltaH;\n\n // Get constraints\n const tileClass = state.tile.constructor;\n const constraints = tileClass.SIZE_CONSTRAINTS || { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n // Apply constraints\n newW = Math.max(constraints.minW, Math.min(newW, constraints.maxW));\n newH = Math.max(constraints.minH, Math.min(newH, constraints.maxH));\n\n // Don't exceed grid width\n newW = Math.min(newW, this.columns - state.x);\n\n // Live update tile size\n state.tile.element.style.gridColumn = `${state.x + 1} / span ${newW}`;\n state.tile.element.style.gridRow = `${state.y + 1} / span ${newH}`;\n\n state.pendingW = newW;\n state.pendingH = newH;\n }\n\n /**\n * Handle pointer up (end drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerUp(e) {\n if (this._dragState) {\n this._onDragEnd();\n } else if (this._resizeState) {\n this._onResizeEnd();\n }\n }\n\n /**\n * Handle drag end.\n * @private\n */\n _onDragEnd() {\n const state = this._dragState;\n if (!state) return;\n\n state.tile.element.classList.remove('dragging');\n this._removeGhost();\n\n // Update layout if position changed\n if (state.pendingX !== undefined && state.pendingY !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.x = state.pendingX;\n layoutItem.y = state.pendingY;\n this._applyTilePosition(state.tile, layoutItem);\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n }\n }\n\n this._dragState = null;\n }\n\n /**\n * Handle resize end.\n * @private\n */\n _onResizeEnd() {\n const state = this._resizeState;\n if (!state) return;\n\n state.tile.element.classList.remove('resizing');\n\n // Update layout if size changed\n if (state.pendingW !== undefined && state.pendingH !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.w = state.pendingW;\n layoutItem.h = state.pendingH;\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n\n // Re-render tile content for new size\n if (this.data) {\n state.tile.fullData = this.fullData;\n state.tile.update(this.data);\n } else {\n // Re-rendering from a dataset already in hand is free; asking\n // the server again because a tile got 40 px wider is not. A\n // self-fetching tile \u2014 or one the embedder feeds through\n // `setData` \u2014 is told the geometry settled and decides what\n // that costs it \u2014 for a chart, one `Plotly.Plots.resize`.\n state.tile.onResize?.();\n }\n }\n }\n\n this._resizeState = null;\n }\n\n /**\n * Check if two layout items overlap.\n * @param {Object} a - First layout item {x, y, w, h}\n * @param {Object} b - Second layout item {x, y, w, h}\n * @returns {boolean}\n * @private\n */\n _tilesOverlap(a, b) {\n return !(\n a.x + a.w <= b.x ||\n b.x + b.w <= a.x ||\n a.y + a.h <= b.y ||\n b.y + b.h <= a.y\n );\n }\n\n /**\n * Resolve overlaps by pushing tiles down.\n * @param {string} sourceTileId - The tile that was resized/moved\n * @private\n */\n _resolveOverlaps(sourceTileId) {\n const sourceItem = this.layout.find(l => l.id === sourceTileId);\n if (!sourceItem) return;\n\n // Sort tiles by y position (top to bottom), then by x\n const otherTiles = this.layout\n .filter(l => l.id !== sourceTileId)\n .sort((a, b) => a.y - b.y || a.x - b.x);\n\n let hasChanges = true;\n let iterations = 0;\n const maxIterations = 100; // Prevent infinite loops\n\n while (hasChanges && iterations < maxIterations) {\n hasChanges = false;\n iterations++;\n\n for (const item of otherTiles) {\n if (this._tilesOverlap(sourceItem, item)) {\n // Push this tile down to be below the source tile\n const newY = sourceItem.y + sourceItem.h;\n if (item.y !== newY) {\n item.y = newY;\n hasChanges = true;\n\n // Apply the new position visually\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n // Check for cascading overlaps among the moved tiles\n for (let i = 0; i < otherTiles.length; i++) {\n for (let j = i + 1; j < otherTiles.length; j++) {\n if (this._tilesOverlap(otherTiles[i], otherTiles[j])) {\n // Push the lower-index tile (earlier in sort order) doesn't need to move\n // Push the higher one down\n const pusher = otherTiles[i];\n const pushed = otherTiles[j];\n const newY = pusher.y + pusher.h;\n if (pushed.y < newY && this._tilesOverlap(pusher, pushed)) {\n pushed.y = newY;\n hasChanges = true;\n\n const tile = this.tiles.get(pushed.id);\n if (tile) {\n this._applyTilePosition(tile, pushed);\n }\n }\n }\n }\n }\n }\n\n // Compact the layout - remove vertical gaps\n this._compactLayout();\n }\n\n /**\n * Compact the layout by removing vertical gaps.\n * @private\n */\n _compactLayout() {\n // Sort tiles by y position\n const sortedTiles = [...this.layout].sort((a, b) => a.y - b.y || a.x - b.x);\n\n for (const item of sortedTiles) {\n // Try to move up as far as possible\n let newY = 0;\n\n while (newY < item.y) {\n const testPosition = { ...item, y: newY };\n\n // Check for overlaps with tiles above this one\n let hasOverlap = false;\n for (const other of this.layout) {\n if (other.id === item.id) continue;\n if (this._tilesOverlap(testPosition, other)) {\n hasOverlap = true;\n // Move below this overlapping tile\n newY = other.y + other.h;\n break;\n }\n }\n\n if (!hasOverlap) {\n break;\n }\n }\n\n if (newY < item.y) {\n item.y = newY;\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n /**\n * Create ghost element for drag preview.\n * @param {DOMRect} rect - Original tile rect\n * @private\n */\n _createGhost(rect) {\n this._ghostElement = document.createElement('div');\n this._ghostElement.className = 'tile-ghost';\n this.gridElement.appendChild(this._ghostElement);\n }\n\n /**\n * Remove ghost element.\n * @private\n */\n _removeGhost() {\n if (this._ghostElement) {\n this._ghostElement.remove();\n this._ghostElement = null;\n }\n }\n\n /**\n * Find next available position for a new tile.\n * @param {number} w - Width in cells\n * @param {number} h - Height in cells\n * @returns {{x: number, y: number}}\n */\n findNextPosition(w, h) {\n // Build occupancy grid\n const maxY = Math.max(...this.layout.map(l => l.y + l.h), 0);\n const occupied = new Set();\n\n this.layout.forEach(l => {\n for (let x = l.x; x < l.x + l.w; x++) {\n for (let y = l.y; y < l.y + l.h; y++) {\n occupied.add(`${x},${y}`);\n }\n }\n });\n\n // Find first available position\n for (let y = 0; y <= maxY + 1; y++) {\n for (let x = 0; x <= this.columns - w; x++) {\n let fits = true;\n for (let dx = 0; dx < w && fits; dx++) {\n for (let dy = 0; dy < h && fits; dy++) {\n if (occupied.has(`${x + dx},${y + dy}`)) {\n fits = false;\n }\n }\n }\n if (fits) {\n return { x, y };\n }\n }\n }\n\n // Default: place at bottom\n return { x: 0, y: maxY + 1 };\n }\n\n /**\n * Handle tile config request.\n * @param {CustomEvent} e\n * @private\n */\n _onTileConfigRequest(e) {\n const { tileId, tileType, config, schema } = e.detail;\n this.eventBus?.emit?.('grid:config-modal-show', {\n tileId,\n tileType,\n config,\n schema,\n variables: this.data ? this._getVariableList() : [],\n onSave: (newConfig) => {\n const tile = this.tiles.get(tileId);\n if (tile) {\n tile.fullData = this.fullData;\n tile.update(this.data, newConfig);\n // A saved config is usually a changed BINDING, and the data\n // source's cache is keyed by the old one \u2014 so this is the one\n // reload that must not be served from it.\n if (this.dataSource) tile.loadData?.({ force: true });\n // Update layout config\n const layoutItem = this.layout.find(l => l.id === tileId);\n if (layoutItem) {\n layoutItem.config = newConfig;\n }\n this._emitLayoutChanged();\n }\n }\n });\n }\n\n /**\n * Handle tile remove request.\n * Note: Let the event bubble up to the dashboard which handles confirmation.\n * @param {CustomEvent} e\n * @private\n */\n _onTileRemoveRequest(e) {\n // Don't auto-remove - let event bubble up to dashboard\n // Dashboard shows a confirm dialog before calling removeTile()\n // Do NOT stop propagation - dashboard listener needs to receive this event\n }\n\n /**\n * Get list of available variables from data.\n * @returns {Array<{value: string, label: string}>}\n * @private\n */\n _getVariableList() {\n if (!this.data) return [];\n\n const variables = [];\n if (this.data.stocks) {\n Object.keys(this.data.stocks).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n if (this.data.indicators) {\n Object.keys(this.data.indicators).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n return variables;\n }\n\n /**\n * Show add widget menu.\n * @private\n */\n _showAddWidgetMenu() {\n this.eventBus?.emit?.('grid:add-widget-menu-show', {\n onSelect: (type) => {\n const { getWidget } = require('./tile_registry.js');\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n }\n });\n }\n\n /**\n * Reset to default layout.\n * @private\n */\n _resetLayout() {\n this.eventBus?.emit?.('grid:reset-layout-confirm', {\n onConfirm: () => {\n this.eventBus?.emit?.('grid:layout-reset-requested');\n }\n });\n }\n\n /**\n * Export report.\n * @private\n */\n _exportReport() {\n this.eventBus?.emit?.('grid:export-requested', {\n gridElement: this.gridElement,\n layout: this.getLayout()\n });\n }\n\n /**\n * Notify that a layout mutation is about to begin (drag/resize start).\n * @private\n */\n _emitBeforeLayoutChange() {\n if (typeof this._onBeforeLayoutChangeCallback === 'function') {\n this._onBeforeLayoutChangeCallback(this.getLayout());\n }\n }\n\n /**\n * Emit layout changed event and call the onLayoutChange callback.\n * @private\n */\n _emitLayoutChanged() {\n const layout = this.getLayout();\n this.eventBus?.emit?.('grid:layout-changed', { layout });\n\n // Call the callback if provided (used by ResultsTileDashboard for autosave)\n if (typeof this._onLayoutChangeCallback === 'function') {\n this._onLayoutChangeCallback(layout);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose() {\n document.removeEventListener('pointermove', this._boundOnPointerMove);\n document.removeEventListener('pointerup', this._boundOnPointerUp);\n\n this._addWidgetDropdown?.destroy();\n this._addWidgetDropdown = null;\n\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n if (this.gridElement) {\n this.gridElement.remove();\n this.gridElement = null;\n }\n }\n}\n\nexport default TileGrid;\n", "/**\n * @flexdesk/tiles \u2014 A draggable, resizable widget grid: the tile base class, the grid, the\n * widget registry, layout persistence, a chart and a KPI tile (0.13.0), a list and a\n * people tile and a board-wide scope picker (0.16.1).\n *\n * It stores layouts under keys YOU choose and resolves starting templates\n * through a callback YOU supply. It has no opinion about what a layout is\n * keyed by.\n *\n * GENERATED by scripts/gen_barrels.py. Do not hand-edit. (0.13.0: hand-edited to\n * add chart_tiles.js \u2014 the generator is not in this repository; 0.16.1: list_tiles.js\n * and scope_picker.js, the same way.)\n *\n * 8 modules.\n */\n\nexport * from './src/tiles/chart_tiles.js';\nexport * from './src/tiles/config_schema.js';\nexport * from './src/tiles/layout_persistence.js';\nexport * from './src/tiles/list_tiles.js';\nexport * from './src/tiles/scope_picker.js';\nexport * from './src/tiles/tile_base.js';\nexport * from './src/tiles/tile_grid.js';\nexport * from './src/tiles/tile_registry.js';\n"],
5
- "mappings": "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",
6
- "names": ["el", "el", "traces", "applyTitle", "getWidget"]
3
+ "sources": ["../src/tiles/config_schema.js", "../src/tiles/tile_base.js", "../src/tiles/figure_tile.js", "../src/tiles/chart_tiles.js", "../src/tiles/layout_persistence.js", "../src/tiles/list_tiles.js", "../src/tiles/scope_picker.js", "../src/tiles/tile_config_form.js", "../src/tiles/tile_grid.js", "../tiles.js"],
4
+ "sourcesContent": ["/**\n * config_schema.js\n *\n * Configuration schema definitions for widget types.\n * Defines field types, validation rules, and default values.\n */\n\nimport { isHexColor } from '../ui/components/color_field.js';\n\n/**\n * Field type definitions for widget configuration.\n */\nexport const FieldTypes = {\n TEXT: 'text',\n NUMBER: 'number',\n CHECKBOX: 'checkbox',\n SELECT: 'select',\n MULTISELECT: 'multiselect',\n COLOR: 'color',\n RANGE: 'range'\n};\n\n/**\n * Validate a configuration value against its field schema.\n * @param {any} value - Value to validate\n * @param {Object} field - Field schema\n * @returns {{valid: boolean, error?: string}} Validation result\n */\nexport function validateField(value, field) {\n // Check required\n if (field.required && (value == null || value === '')) {\n return { valid: false, error: `${field.label} is required` };\n }\n\n // Type-specific validation\n switch (field.type) {\n case FieldTypes.NUMBER:\n case FieldTypes.RANGE:\n if (value != null && value !== '') {\n const num = parseFloat(value);\n if (isNaN(num)) {\n return { valid: false, error: `${field.label} must be a number` };\n }\n if (field.min != null && num < field.min) {\n return { valid: false, error: `${field.label} must be at least ${field.min}` };\n }\n if (field.max != null && num > field.max) {\n return { valid: false, error: `${field.label} must be at most ${field.max}` };\n }\n }\n break;\n\n case FieldTypes.SELECT:\n if (field.required && !value) {\n return { valid: false, error: `${field.label} must be selected` };\n }\n break;\n\n case FieldTypes.COLOR:\n if (value != null && value !== '' && !isHexColor(value)) {\n return { valid: false, error: `${field.label} must be a hex colour (#rgb or #rrggbb)` };\n }\n break;\n\n case FieldTypes.MULTISELECT:\n if (field.required && (!Array.isArray(value) || value.length === 0)) {\n return { valid: false, error: `${field.label} must have at least one selection` };\n }\n break;\n }\n\n return { valid: true };\n}\n\n/**\n * Validate an entire configuration object against a schema.\n * @param {Object} config - Configuration object\n * @param {Object} schema - Schema with fields array\n * @returns {{valid: boolean, errors: Object}} Validation result\n */\nexport function validateConfig(config, schema) {\n const errors = {};\n let valid = true;\n\n if (!schema?.fields) {\n return { valid: true, errors: {} };\n }\n\n schema.fields.forEach(field => {\n const result = validateField(config[field.key], field);\n if (!result.valid) {\n errors[field.key] = result.error;\n valid = false;\n }\n });\n\n return { valid, errors };\n}\n\n/**\n * Merge user config with defaults from schema.\n * @param {Object} config - User configuration\n * @param {Object} schema - Schema with fields array\n * @returns {Object} Merged configuration\n */\nexport function mergeWithDefaults(config, schema) {\n const result = { ...config };\n\n if (schema?.fields) {\n schema.fields.forEach(field => {\n if (result[field.key] === undefined && field.default !== undefined) {\n result[field.key] = field.default;\n }\n });\n }\n\n return result;\n}\n\n/**\n * Get options for a select/multiselect field.\n * Handles dynamic options (e.g., 'variables' which gets populated from data).\n * @param {Object} field - Field schema\n * @param {Object} data - Current data context\n * @returns {Array<{value: string, label: string}>} Options array\n */\nexport function getFieldOptions(field, data) {\n if (Array.isArray(field.options)) {\n return field.options;\n }\n\n // Dynamic options based on string identifier\n if (field.options === 'variables') {\n return getVariableOptions(data);\n }\n\n if (field.options === 'namespaces') {\n return getNamespaceOptions(data);\n }\n\n return [];\n}\n\n/**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n *\n * Examples:\n * \"Agriculture.__SimpleStocks__::arable_land[State]\" \u2192 \"arable_land\"\n * \"Population.population\" \u2192 \"population\"\n * \"Banks::Assets[Cash]\" \u2192 \"Assets / Cash\"\n * \"my_variable\" \u2192 \"my_variable\"\n *\n * @param {string} name - Raw variable key from analytics\n * @returns {string} Friendly display label\n */\nexport function formatVariableLabel(name) {\n if (!name) return '';\n let label = name;\n\n // Strip namespace prefix: \"Namespace.rest\" \u2192 \"rest\"\n const dotIdx = label.indexOf('.');\n if (dotIdx > 0) {\n label = label.slice(dotIdx + 1);\n }\n\n // Strip __SimpleStocks__:: or similar double-underscore sector prefixes\n label = label.replace(/^__\\w+__::/, '');\n\n // Handle Godley stock pattern: \"Sector::AccountType[Account]\" \u2192 \"AccountType / Account\"\n // But first strip [State] / [Rate] suffixes that are internal\n label = label.replace(/\\[State\\]$/i, '');\n label = label.replace(/\\[Rate\\]$/i, '');\n\n // Clean up trailing empty brackets or colons from stripping\n label = label.replace(/\\[\\]$/, '');\n\n // Replace :: with readable separator\n label = label.replace(/::/g, ' / ');\n\n // Replace single colons used as separators with underscore\n label = label.replace(/:/g, '_');\n\n // Clean up any double spaces or leading/trailing whitespace\n return label.replace(/\\s{2,}/g, ' ').trim();\n}\n\n/**\n * Get variable options from data.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string, category?: string}>} Variable options\n */\nexport function getVariableOptions(data) {\n const options = [];\n\n if (!data) return options;\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Stocks'\n });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Flows'\n });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Indicators'\n });\n });\n }\n\n return options;\n}\n\n/**\n * Extract unique namespace names from variable keys in data.\n * Stock keys follow the pattern \"Namespace.Sector::Type[Account]\".\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>}\n */\nexport function getNamespaceOptions(data) {\n const namespaces = new Set();\n const sources = [data?.stocks, data?.flows, data?.indicators];\n for (const source of sources) {\n if (!source) continue;\n for (const key of Object.keys(source)) {\n const dotIdx = key.indexOf('.');\n if (dotIdx > 0) {\n namespaces.add(key.slice(0, dotIdx));\n }\n }\n }\n if (namespaces.size === 0) namespaces.add('Main');\n return Array.from(namespaces).sort().map(ns => ({ value: ns, label: ns }));\n}\n\nexport default {\n FieldTypes,\n validateField,\n validateConfig,\n mergeWithDefaults,\n getFieldOptions,\n getVariableOptions,\n formatVariableLabel\n};\n", "/**\n * tile_base.js\n *\n * Base class for all dashboard widget tiles.\n * Provides common lifecycle management, tile chrome (header, config button),\n * and abstract methods for subclass implementation.\n */\n\nimport { openRawTracesWindow } from '../charts/plot_popout_window.js';\nimport { formatVariableLabel } from './config_schema.js';\n// The host is INJECTED, not fetched from a global.\n//\n// This imported `appHost()` from ui/js/ecoagent/app_host.js \u2014 a tile reaching into\n// the application to find out how to save a file. The framework is injection-only;\n// the app may have a root host provider, but the library does not get to know about\n// it. Its only use was to back \"Expand\" -> Export CSV/PNG, and a tile without a host\n// falls back to a Blob download, which is exactly what the host contract promises.\n\nexport class TileBase {\n /** @type {string} Widget type identifier - override in subclass */\n static TYPE = 'base';\n\n /** @type {string} Display title - override in subclass */\n static TITLE = 'Widget';\n\n /** @type {{w: number, h: number}} Default grid size - override in subclass */\n static DEFAULT_SIZE = { w: 4, h: 3 };\n\n /** @type {{minW: number, minH: number, maxW: number, maxH: number}} Size constraints */\n static SIZE_CONSTRAINTS = { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n /** @type {boolean} Whether widget can be expanded to a separate window - override in subclass */\n static EXPANDABLE = false;\n\n /** @type {boolean} Whether widget supports scenario comparison overlay - override in subclass */\n static SUPPORTS_COMPARISON = false;\n\n /**\n * @param {Object} options\n * @param {string} options.id - Unique tile identifier\n * @param {Object} options.grid - Parent TileGrid instance\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {Object} [options.config] - Widget-specific configuration\n * @param {boolean} [options.headless] - If true, mount without tile chrome (header, controls)\n * @param {{resolve: Function}} [options.dataSource] - Where this tile asks for its\n * own rows. Handed down by `TileGrid`; absent for a grid whose data is\n * broadcast with `setData()`, and then nothing ever calls `loadData()`.\n */\n constructor({ id, grid, eventBus = null, config = {}, readonly = false,\n headless = false, host = null, stateGuard = null,\n dataSource = null }) {\n this.host = host;\n // THE TILE PULLS; THE GRID DOES NOT PUSH.\n //\n // `TileGrid.setData()` broadcasts one dataset to every tile, which is the\n // right shape when every tile reads the same simulation run and the wrong\n // one when each tile is bound to a different query \u2014 the second tile would\n // then have to find its own rows inside a payload it never asked for. A\n // data source is anything answering `resolve(tileId, binding)`; the base\n // class only holds it and hands it to `loadData()`, so a grid constructed\n // without one behaves exactly as it did before this line existed, and the\n // broadcast path is untouched.\n this.dataSource = dataSource;\n // This used to be read off an application's window global \u2014 reached for\n // by a tile. The StateGuard is a FRAMEWORK service (@flexdesk/core); the INSTANCE is\n // the application's, and it is handed down through the grid. No guard => the\n // dataset writes happen directly, which is what the optional chain already did.\n this.stateGuard = stateGuard;\n this.id = id;\n this.grid = grid;\n this.eventBus = eventBus;\n this.config = { ...this.getDefaultConfig(), ...config };\n this.readonly = readonly;\n this.headless = headless;\n this.element = null;\n this.contentElement = null;\n this.chartInstance = null;\n this.data = null;\n /** @type {Object|null} Unfiltered analytics data for cross-namespace variable resolution */\n this.fullData = null;\n this._disposed = false;\n // Written by whatever implements `loadData()`. `_loadSeq` is the guard\n // against a slow first request landing after a fast second one and\n // painting stale rows over fresh ones \u2014 a tile is re-resolved on every\n // filter change, so that race is the normal case rather than the edge.\n this._lastLoadedAt = null;\n this._loadSeq = 0;\n /** @type {Map<string, {name: string, analytics: Object, color: string}>|null} */\n this.comparisonData = null;\n /** The board's scope (`TileGrid.setScope`), or null. Set before mount. */\n this.scope = null;\n }\n\n /**\n * Called when the board's scope changes (`TileGrid.setScope`), after\n * `this.scope` is set. A no-op here: a tile whose rows the grid's data\n * source loads is reloaded by the grid, and one fed through `setData` is\n * fed again by whoever owns its data.\n * @param {*} _scope\n */\n onScopeChange(_scope) {}\n\n /**\n * Set comparison data for overlay rendering.\n * Only meaningful for widgets where SUPPORTS_COMPARISON = true.\n * @param {Map<string, Object>|null} comparisonData\n */\n setComparisonData(comparisonData) {\n this.comparisonData = comparisonData;\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n * @param {string} name - Raw variable key\n * @returns {string} Friendly display label\n */\n formatLabel(name) {\n return formatVariableLabel(name);\n }\n\n /**\n * Look up the unit string for a variable from analytics metadata.\n * Checks stocks, flows, and indicators for unit metadata.\n * @param {string} varName - Variable name\n * @returns {string|null} Unit string or null\n */\n getVariableUnit(varName) {\n if (!varName || !this.data) return null;\n const sources = [this.data.stocks, this.data.flows, this.data.indicators];\n for (const source of sources) {\n const varData = source?.[varName];\n if (varData?.unit) return varData.unit;\n }\n return null;\n }\n\n /**\n * Look up a variable across stocks, flows, and indicators.\n * If the variable is not found, returns the first available variable\n * and updates the config key so the widget self-heals.\n * @param {Object} data - Analytics data\n * @param {string} configKey - Config property name (e.g. 'variable', 'xVariable')\n * @returns {{varData: any, varName: string}|null} Resolved data or null if no data at all\n */\n resolveVariable(data, configKey = 'variable') {\n const varName = this.config[configKey];\n if (varName) {\n // Try exact name first\n const varData = data.stocks?.[varName]\n || data.indicators?.[varName]\n || data.flows?.[varName];\n if (varData) return { varData, varName };\n\n // Try without namespace prefix (e.g. \"Population.population\" \u2192 \"population\")\n const dotIdx = varName.indexOf('.');\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const bareData = data.stocks?.[bare]\n || data.indicators?.[bare]\n || data.flows?.[bare];\n if (bareData) return { varData: bareData, varName: bare };\n }\n\n // Reverse lookup: bare name \u2192 namespace-prefixed key\n // e.g. \"population\" matches \"Population.population\" in MC data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n\n // Try unfiltered data (variable may be in a different namespace)\n if (this.fullData && this.fullData !== data) {\n const fullVarData = this.fullData.stocks?.[varName]\n || this.fullData.indicators?.[varName]\n || this.fullData.flows?.[varName];\n if (fullVarData) return { varData: fullVarData, varName };\n\n // Also try bare name against unfiltered data\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const fullBareData = this.fullData.stocks?.[bare]\n || this.fullData.indicators?.[bare]\n || this.fullData.flows?.[bare];\n if (fullBareData) return { varData: fullBareData, varName: bare };\n }\n\n // Reverse lookup against unfiltered data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [this.fullData.stocks, this.fullData.indicators, this.fullData.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n }\n }\n\n // Configured variable not found \u2014 auto-select the first available\n const sources = [data.stocks, data.indicators, data.flows];\n for (const source of sources) {\n if (!source) continue;\n const keys = Object.keys(source);\n if (keys.length > 0) {\n this.config[configKey] = keys[0];\n return { varData: source[keys[0]], varName: keys[0] };\n }\n }\n\n return null;\n }\n\n /**\n * Find a variable by name in data, trying exact match then suffix match.\n * Does NOT auto-fallback to first available variable.\n * @param {Object} data - Analytics data with stocks/indicators/flows\n * @param {string} varName - Variable name (bare or namespace-prefixed)\n * @returns {{varData: any, varName: string}|null}\n */\n static findVariable(data, varName) {\n if (!data || !varName) return null;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[varName]) return { varData: source[varName], varName };\n }\n // Reverse lookup: bare \"population\" \u2192 \"Population.population\"\n const dotIdx = varName.indexOf('.');\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n } else {\n // Strip prefix: \"Population.population\" \u2192 \"population\"\n const bare = varName.slice(dotIdx + 1);\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[bare]) return { varData: source[bare], varName: bare };\n }\n }\n return null;\n }\n\n /**\n * Get default configuration for this widget type.\n * Override in subclass.\n * @returns {Object} Default config object\n */\n getDefaultConfig() {\n return {};\n }\n\n /**\n * Get configuration schema for the config modal.\n * Override in subclass.\n * @returns {Object} Schema definition\n */\n getConfigSchema() {\n return { fields: [] };\n }\n\n /**\n * Render widget content with data.\n * Override in subclass.\n * @param {Object} data - Analytics data\n */\n render(data) {\n throw new Error('TileBase.render() must be implemented by subclass');\n }\n\n /**\n * Mount the tile into the container.\n * @param {HTMLElement} container - Parent container\n */\n mount(container) {\n if (this._disposed) return;\n\n this.element = document.createElement('div');\n this.element.className = `tile${this.readonly ? ' tile--readonly' : ''}`;\n\n // Use StateGuard bypass if available to set dataset properties\n const stateGuard = this.stateGuard;\n const setDataset = () => {\n this.element.dataset.tileId = this.id;\n this.element.dataset.tileType = this.constructor.TYPE;\n };\n if (stateGuard?.executeWithBypass) {\n stateGuard.executeWithBypass('tile-mount', setDataset);\n } else {\n setDataset();\n }\n\n if (this.headless) {\n // Headless mode: content only, no header/controls (for embedding in notebook cells)\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n this.element.appendChild(this.contentElement);\n } else {\n // Build tile chrome (header + content area)\n this._buildChrome();\n }\n\n container.appendChild(this.element);\n }\n\n /**\n * Update the widget with new data and/or config.\n * @param {Object} [data] - New analytics data\n * @param {Object} [config] - New config values to merge\n */\n update(data, config) {\n if (this._disposed) return;\n\n if (config) {\n const prevDocs = (this.config?.docs || '').trim();\n this.config = { ...this.config, ...config };\n const nextDocs = (this.config?.docs || '').trim();\n // Keep the header's info-button in sync with the docs state\n if (this.element && !this.headless && prevDocs !== nextDocs) {\n this._syncInfoButton();\n }\n }\n\n if (data !== undefined) {\n this.data = data;\n }\n\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /**\n * Load this tile's own data from `this.dataSource` and render it.\n *\n * A NO-OP HERE ON PURPOSE. The base class knows nothing about what a binding\n * is or what a dataset looks like \u2014 those belong to the consumer, and the\n * consumer that has them (Tables' `TablesTile`) implements this in ~30 lines\n * over `showLoading()` / `render()` / `showError()`. What upstream owns is the\n * CALL SITES: `TileGrid` invokes this after mount, after a resize settles and\n * after a config save, but only when a `dataSource` was injected. Making it a\n * hook rather than an implementation is what keeps EcoAgent's broadcast path\n * (`setData` -> `update`) bit-identical: with no data source nothing here ever\n * runs.\n *\n * @param {{force?: boolean}} [_opts] - `force` bypasses the source's cache.\n * @returns {Promise<void>}\n */\n async loadData(_opts = {}) {}\n\n /**\n * Called once after a drag-resize settles, for widgets whose content does not\n * reflow on its own \u2014 a Plotly figure sizes itself at draw time and stays that\n * size until something calls `Plotly.Plots.resize`. Deliberately NOT wired to a\n * ResizeObserver: the grid already knows when a resize ended, and an observer\n * per tile fires during the drag, which is a relayout per pointer-move.\n */\n onResize() {}\n\n /** Add, update, or remove the info (\u24D8) button in the header to match current docs state. */\n _syncInfoButton() {\n const header = this.element?.querySelector('.tile-header');\n const controls = header?.querySelector('.tile-controls');\n if (!controls) return;\n const docs = (this.config?.docs || '').trim();\n let btn = controls.querySelector('.tile-info-btn');\n if (docs) {\n if (!btn) {\n btn = document.createElement('button');\n btn.className = 'tile-info-btn twm-has-tooltip';\n btn.type = 'button';\n btn.tabIndex = -1;\n btn.style.cssText = 'background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;';\n btn.setAttribute('data-tooltip-placement', 'bottom');\n btn.setAttribute('data-tooltip-max-width', '420px');\n btn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>';\n btn.addEventListener('click', (e) => e.stopPropagation());\n const anchor = controls.querySelector('.tile-expand-btn')\n ?? controls.querySelector('.tile-remove-btn');\n if (anchor) controls.insertBefore(btn, anchor);\n else controls.appendChild(btn);\n }\n btn.setAttribute('data-tooltip', docs);\n } else if (btn) {\n btn.remove();\n }\n }\n\n /**\n * Clean up resources and remove from DOM.\n */\n dispose() {\n if (this._disposed) return;\n this._disposed = true;\n\n // Close expand window if open\n if (this._expandWindow?.isVisible) {\n this._expandWindow.close();\n }\n this._expandWindow = null;\n\n // Destroy chart instance if exists\n if (this.chartInstance) {\n this.chartInstance.destroy();\n this.chartInstance = null;\n }\n\n // Remove from DOM\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n\n this.element = null;\n this.contentElement = null;\n this.data = null;\n this.fullData = null;\n }\n\n /**\n * The entries in the tile's \u22EF menu, as `{action, label, icon, hidden}`.\n *\n * This existed as a LITERAL inside `_buildChrome`, and the literal was\n * EcoAgent's: \"Add to Documentation\" and \"Show in Documentation\". Both are\n * meaningful only for a tile whose `config.sourceCellId` names a notebook\n * cell, and the first one's hide condition is `sourceCellId && already-added` \u2014\n * so on a tile that has no `sourceCellId` at all it renders VISIBLE, and\n * choosing it emits `tile:add-to-documentation` at an application that has no\n * documentation. Every consumer other than EcoAgent therefore shipped a menu\n * item that did nothing, and could not remove it without editing this file.\n *\n * Returning `[]` drops the whole wrapper \u2014 button, dropdown and all \u2014 because\n * a \u22EF button that opens an empty menu reads as a broken feature rather than\n * an absent one. The default is the two entries above, so EcoAgent's chrome\n * is unchanged.\n *\n * Selection is routed through `_onMenuAction()`; override both together.\n * @returns {Array<{action: string, label: string, icon?: string, hidden?: boolean}>}\n */\n menuItems() {\n const linked = !!(this.config?.sourceCellId\n && this.grid?.documentationCellIds?.has(this.config.sourceCellId));\n return [\n { action: 'add-to-documentation',\n label: 'Add to Documentation', icon: 'post_add', hidden: linked },\n { action: 'show-in-documentation',\n label: 'Show in Documentation', icon: 'description', hidden: !linked },\n ];\n }\n\n /**\n * Act on a \u22EF menu selection. One dispatch point for every entry, so an\n * override of `menuItems()` cannot add a row that has nothing behind it, and\n * an unrecognised action is silently ignored rather than throwing into a\n * click handler.\n * @param {string} action\n * @protected\n */\n _onMenuAction(action) {\n if (action === 'add-to-documentation') {\n this.eventBus?.emit?.('tile:add-to-documentation', {\n tileType: this.constructor.TYPE,\n config: { ...this.config },\n });\n } else if (action === 'show-in-documentation') {\n if (this.config?.sourceCellId) {\n this.eventBus?.emit?.('tile:show-in-documentation', {\n sourceCellId: this.config.sourceCellId,\n });\n }\n }\n }\n\n /**\n * Build the tile chrome (header, content area, resize handles).\n * @private\n */\n _buildChrome() {\n // Header with drag handle and controls\n const header = document.createElement('div');\n header.className = 'tile-header';\n\n // Build controls HTML - expand button only if widget is expandable\n const expandBtnHtml = this.constructor.EXPANDABLE\n ? `<button class=\"tile-expand-btn twm-has-tooltip\" data-tooltip=\"Open in window\">\n <span class=\"material-symbols-outlined\">open_in_new</span>\n </button>`\n : '';\n\n // Info button \u2014 only shown if config.docs has text. Uses the\n // standard has-tooltip system so the docs appear as a hover tooltip\n // (auto-positioned) instead of a click-to-open popover.\n const docs = (this.config?.docs || '').trim();\n const infoBtnHtml = docs\n ? `<button class=\"tile-info-btn twm-has-tooltip\" type=\"button\" tabindex=\"-1\"\n data-tooltip=\"${this.#escapeAttr(docs)}\"\n data-tooltip-placement=\"bottom\"\n data-tooltip-max-width=\"420px\"\n style=\"background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;\">\n <span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>\n </button>`\n : '';\n\n // The \u22EF menu, from `menuItems()` rather than from a literal. Read-only\n // chrome never had one, so the hook is not even asked in that mode.\n const menuEntries = (this.readonly ? [] : this.menuItems()) ?? [];\n const menuHtml = menuEntries.length\n ? `<div class=\"tile-menu-wrapper\">\n <button class=\"tile-menu-btn twm-has-tooltip\" data-tooltip=\"More actions\">\n <span class=\"material-symbols-outlined\">more_vert</span>\n </button>\n <div class=\"tile-menu-dropdown\" hidden>\n ${menuEntries.map((item) => `\n <button class=\"tile-menu-item\" data-action=\"${this.#escapeAttr(item.action)}\"${item.hidden ? ' style=\"display:none\"' : ''}>\n ${item.icon ? `<span class=\"material-symbols-outlined\">${this.#escapeAttr(item.icon)}</span>` : ''}\n <span>${this.#escapeAttr(item.label ?? '')}</span>\n </button>`).join('')}\n </div>\n </div>`\n : '';\n\n if (this.readonly) {\n // Read-only mode: no drag handle, no menu, no remove button\n header.innerHTML = `\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n ${infoBtnHtml}\n ${expandBtnHtml}\n </div>\n `;\n } else {\n header.innerHTML = `\n <span class=\"tile-drag-handle twm-has-tooltip\" data-tooltip=\"Drag to reposition\">\n <span class=\"material-symbols-outlined\">drag_indicator</span>\n </span>\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n <button class=\"tile-config-btn twm-has-tooltip\" data-tooltip=\"Configure\">\n <span class=\"material-symbols-outlined\">settings</span>\n </button>\n ${menuHtml}\n ${infoBtnHtml}\n ${expandBtnHtml}\n <button class=\"tile-remove-btn twm-has-tooltip\" data-tooltip=\"Remove widget\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n `;\n }\n\n // Expand button handler\n const expandBtn = header.querySelector('.tile-expand-btn');\n expandBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onExpandClick();\n });\n\n // Info button is purely decorative \u2014 the docs are shown by the global\n // tooltip service via data-tooltip. Stop click-propagation so clicks\n // don't open the config panel, and make the button unfocusable.\n const infoBtn = header.querySelector('.tile-info-btn');\n infoBtn?.addEventListener('click', (e) => e.stopPropagation());\n\n if (!this.readonly) {\n // Config opens ONLY via the explicit cogwheel button \u2014 not a\n // title or content click, which fired the config panel too\n // eagerly (e.g. when you just wanted to read or pan the chart).\n const configBtn = header.querySelector('.tile-config-btn');\n configBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onConfigClick();\n });\n\n // \"...\" menu button + dropdown\n const menuBtn = header.querySelector('.tile-menu-btn');\n const menuDropdown = header.querySelector('.tile-menu-dropdown');\n if (menuBtn && menuDropdown) {\n menuBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const isOpen = !menuDropdown.hidden;\n menuDropdown.hidden = !menuDropdown.hidden;\n if (!isOpen) {\n // Close on outside click\n const closeMenu = (ev) => {\n if (!menuDropdown.contains(ev.target) && ev.target !== menuBtn) {\n menuDropdown.hidden = true;\n document.removeEventListener('pointerdown', closeMenu, true);\n }\n };\n // Delay to avoid immediate close from the same click\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', closeMenu, true);\n });\n }\n });\n // One listener per rendered entry, dispatching by `data-action`\n // into `_onMenuAction`. Wiring each action by name here is what\n // made the menu un-overridable: a subclass could add a row and\n // could not add the handler behind it.\n menuDropdown.querySelectorAll('.tile-menu-item').forEach((itemEl) => {\n itemEl.addEventListener('click', (e) => {\n e.stopPropagation();\n menuDropdown.hidden = true;\n this._onMenuAction(itemEl.dataset.action);\n });\n });\n }\n\n const removeBtn = header.querySelector('.tile-remove-btn');\n removeBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onRemoveClick();\n });\n }\n\n // Content area. Clicking the content no longer opens config \u2014 that\n // moved to the explicit cogwheel button in the header so chart\n // interaction (pan/zoom/hover) doesn't trip the config panel.\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n\n this.element.appendChild(header);\n this.element.appendChild(this.contentElement);\n\n if (!this.readonly) {\n // Resize handle (bottom-right)\n const resizeHandle = document.createElement('div');\n resizeHandle.className = 'tile-resize-handle se';\n resizeHandle.innerHTML = '<span class=\"material-symbols-outlined\">drag_handle</span>';\n this.element.appendChild(resizeHandle);\n\n // Context menu for \"Add to Documentation\" etc.\n this.element.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.eventBus?.emit?.('tile:context-menu', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n tileTitle: this.constructor.TITLE,\n config: { ...this.config },\n clientX: e.clientX,\n clientY: e.clientY,\n });\n });\n }\n }\n\n /**\n * Handle config button click \u2014 highlight tile and emit config request.\n * @private\n */\n _onConfigClick() {\n // Deselect all sibling tiles, then select this one\n this.element?.closest('.tile-grid')\n ?.querySelectorAll('.tile.tile--selected')\n .forEach(el => el.classList.remove('tile--selected'));\n this.element?.classList.add('tile--selected');\n\n // Emit event for grid/dashboard to show config panel\n this.eventBus?.emit?.('tile:config-request', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n });\n\n // Also dispatch DOM event for alternative handling\n this.element?.dispatchEvent(new CustomEvent('tile:config-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n }\n }));\n }\n\n /**\n * Handle remove button click.\n * @param {Event} [event] - Original click event\n * @private\n */\n _onRemoveClick(event) {\n const removeBtn = this.element?.querySelector('.tile-remove-btn');\n\n // Only dispatch DOM event - let the dashboard handle confirmation\n this.element?.dispatchEvent(new CustomEvent('tile:remove-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n anchorElement: removeBtn\n }\n }));\n }\n\n /**\n * Set the title displayed in the header.\n * @param {string} title - New title text\n */\n setTitle(title) {\n const titleEl = this.element?.querySelector('.tile-title');\n if (titleEl) {\n titleEl.textContent = title;\n }\n }\n\n /**\n * Show loading state in content area.\n */\n showLoading() {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-loading\">\n <span class=\"material-symbols-outlined spinning\">progress_activity</span>\n <span>Loading...</span>\n </div>\n `;\n }\n }\n\n /**\n * Show empty state in content area.\n *\n * The message is ESCAPED. Both this and `showError` interpolated straight\n * into `innerHTML`, and the string reaching `showError` is the one place a\n * caller has least control over \u2014 a server's error text, echoed back with a\n * column name or a filter value in it. Callers pass plain text; this decides\n * what that means in HTML.\n *\n * @param {string} [message] - Custom message\n */\n showEmpty(message = 'No data available') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-empty\">\n <span class=\"material-symbols-outlined\">inbox</span>\n <span>${this.#escapeAttr(message)}</span>\n </div>\n `;\n }\n }\n\n /**\n * Show error state in content area. The message is escaped \u2014 see `showEmpty`.\n * @param {string} [message] - Error message\n */\n showError(message = 'Failed to load data') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"twm-tile-error\">\n <span class=\"material-symbols-outlined\">error</span>\n <span>${this.#escapeAttr(message)}</span>\n </div>\n `;\n }\n }\n\n /**\n * Format a number for display.\n * @param {number} value - Number to format\n * @param {number} [decimals=2] - Decimal places\n * @returns {string} Formatted string\n */\n formatNumber(value, decimals = 2) {\n if (value == null || !Number.isFinite(value)) return '\u2014';\n\n const abs = Math.abs(value);\n if (abs >= 1e9) {\n return (value / 1e9).toFixed(1) + 'B';\n } else if (abs >= 1e6) {\n return (value / 1e6).toFixed(1) + 'M';\n } else if (abs >= 1e3) {\n return (value / 1e3).toFixed(1) + 'K';\n } else if (abs < 0.01 && abs > 0) {\n return value.toExponential(decimals);\n }\n return value.toFixed(decimals);\n }\n\n /**\n * Get available variables from data for config dropdowns.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>} Variable options\n */\n getAvailableVariables(data) {\n if (!data) return [];\n\n const variables = [];\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n variables.push({ value: name, label: name, category: 'Stocks' });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n variables.push({ value: name, label: name, category: 'Flows' });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n variables.push({ value: name, label: name, category: 'Indicators' });\n });\n }\n\n return variables;\n }\n\n // =========================================================================\n // EXPAND WINDOW FUNCTIONALITY\n // Reuses PlotPopoutWindow's patterns and CSS classes\n // =========================================================================\n\n /**\n * Handle expand button click.\n * @private\n */\n _onExpandClick() {\n if (!this.constructor.EXPANDABLE) return;\n\n const expandData = this.getExpandData();\n if (!expandData) {\n console.warn(`[TileBase] No expand data from widget ${this.id}`);\n return;\n }\n\n this._openExpandWindow(expandData);\n }\n\n /**\n * Get data for the expanded window.\n * Override in subclass for expandable widgets.\n * @returns {Object|null} { title, traces, layout, tableHeaders, tableRows }\n */\n getExpandData() {\n return null;\n }\n\n /**\n * Open the expand window with plot and data tabs.\n * Delegates to openRawTracesWindow (PlotPopoutWindow module) which\n * provides proper toolbar layout, download buttons, and data table.\n * @param {Object} expandData - Data from getExpandData()\n * @private\n */\n async _openExpandWindow(expandData) {\n if (this._expandWindow?.isVisible) {\n this._expandWindow.bringToFront();\n return;\n }\n\n this._expandWindow = await openRawTracesWindow({\n host: this.host,\n id: `tile-expand-${this.id}`,\n title: expandData.title || this.constructor.TITLE,\n traces: expandData.traces,\n layout: expandData.layout,\n frames: expandData.frames,\n tableHeaders: expandData.tableHeaders,\n tableRows: expandData.tableRows,\n services: { eventBus: this.eventBus },\n });\n }\n\n /**\n * Escape a string for safe insertion into HTML \u2014 an attribute value or a text\n * node, since the five characters that matter are the same five in both.\n * @private\n */\n #escapeAttr(s) {\n return String(s ?? '').replace(/[&<>\"']/g, c => ({\n '&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'\n }[c]));\n }\n\n /**\n * Show toast notification via eventBus.\n * @private\n */\n _notify(title, message, severity = 'info') {\n this.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n}\n\nexport default TileBase;\n", "/**\n * figure_tile.js \u2014 a tile that draws ONE Plotly figure, and owns the lifecycle\n * of drawing it.\n *\n * A subclass says WHAT to draw and nothing else. It overrides one method:\n *\n * class SpreadTile extends FigureTile {\n * static TYPE = 'myapp.spread';\n * static TITLE = 'Spread';\n * figure(data) {\n * if (!data?.values?.length) return null; // the empty state\n * return {\n * traces: [buildHistogramTrace({ x: data.values })],\n * layout: { margin: { l: 48, r: 16, t: 8, b: 36 } },\n * };\n * }\n * }\n *\n * `figure(data)` answers `{traces, layout?, config?, frames?}` or `null`, and is\n * synchronous: it computes, it does not wait. Everything else is the base's:\n *\n * - it awaits `ensurePlotly()`, so a page that loads Plotly lazily through\n * `setPlotlySource` draws on first view instead of skipping the draw;\n * - it draws through `createChart` (the theme defaults, `scrollZoom` off \u2014 a\n * tile sits on a scrolling board \u2014 and the mode bar hidden; `config` from\n * the figure goes over those), then adds `frames` when there are any;\n * - a draw that finishes after a newer one, or after the tile went empty,\n * loading, errored or disposed, is discarded and its figure purged;\n * - `null` is the empty state (`static EMPTY_MESSAGE`). A subclass that wants\n * to say WHY calls `this.showEmpty(message)` itself and returns `null`;\n * - a `figure()` that throws, or a draw that fails (Plotly absent included),\n * is the error state plus `tile:render-failed {tileId, message}` on the\n * event bus \u2014 never an unhandled rejection;\n * - one relayout when a resize settles (`onResize`), none while drawing;\n * - Download PNG in the \u22EF menu, through the host's `dialogs.saveFile` when the\n * grid was given a host, else a browser download;\n * - Expand opens `openRawTracesWindow` with the last figure drawn;\n * - `onPointClick({customdata, point, tile})` on a click on a mark.\n *\n * `menuItems()` here EXTENDS `TileBase.menuItems()` with Download PNG; a\n * subclass extends these the same way (`[...super.menuItems(), \u2026]`) and routes\n * its own actions through `_onMenuAction`, calling `super` for the rest.\n *\n * \u2550\u2550 EVERY STATE CHANGE INVALIDATES THE FIGURE \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 * `showEmpty`, `showLoading` and `showError` replace the content with\n * `innerHTML`, which detaches the Plotly div without telling Plotly. So each of\n * them here first purges the figure, drops the reference, marks it not drawn,\n * and bumps `_drawSeq` \u2014 and a draw still in flight finds itself stale and\n * purges its own figure instead of marking it drawn.\n */\n\nimport { TileBase } from './tile_base.js';\nimport { createChart, ensurePlotly, purge, resize as resizePlot } from '../charts/plotly_wrapper.js';\n\n/** What every tile's figure is drawn with; a figure's own `config` goes over it. */\nconst FIGURE_CONFIG = Object.freeze({\n scrollZoom: false,\n displayModeBar: false,\n responsive: true,\n});\n\nconst DOWNLOAD_PNG = Object.freeze({ action: 'download-png', label: 'Download PNG', icon: 'image' });\n\nexport class FigureTile extends TileBase {\n static TYPE = 'flexdesk.figure';\n static TITLE = 'Figure';\n static EXPANDABLE = true;\n /** The empty state's text when `figure()` answers `null`. */\n static EMPTY_MESSAGE = 'No data to show.';\n\n /**\n * @param {Object} options - TileBase's, plus:\n * @param {Function} [options.onPointClick] - `({customdata, point, tile})`\n * on a click on a mark. Also assignable later as `tile.onPointClick`.\n */\n constructor(options = {}) {\n super(options);\n this.onPointClick = typeof options.onPointClick === 'function' ? options.onPointClick : null;\n this._plotEl = null;\n this._drawn = false;\n this._drawSeq = 0;\n /** The figure on screen, once drawn; what Expand opens. */\n this._figure = null;\n }\n\n /**\n * The one override: what to draw for `data`.\n * @param {*} _data\n * @returns {{traces: Array, layout?: Object, config?: Object, frames?: Array}|null}\n */\n figure(_data) {\n throw new Error(`${this.constructor.name}.figure() must be implemented by the subclass`);\n }\n\n /**\n * Hand this tile its data. Unlike `update()`, an empty or null value is\n * drawn \u2014 as the empty state \u2014 rather than ignored.\n */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n /**\n * Kick off the draw and return. Deliberately not `async`: nothing awaits\n * `render`, so a returned promise would be a rejection nobody catches.\n */\n render(data) {\n this._draw(data);\n }\n\n /** One relayout when a resize settles; nothing while a draw is in flight. */\n onResize() {\n if (!this._plotEl || !this._drawn) return;\n resizePlot(this._plotEl).catch(() => {});\n }\n\n menuItems() {\n return [...super.menuItems(), ...this._figureMenuItems()];\n }\n\n /** The entries this class adds to the menu: Download PNG. For a subclass\n * that wants them WITHOUT `TileBase`'s own. @protected */\n _figureMenuItems() {\n return [{ ...DOWNLOAD_PNG }];\n }\n\n _onMenuAction(action) {\n if (action === DOWNLOAD_PNG.action) this._downloadPng();\n else super._onMenuAction(action);\n }\n\n /** The last figure drawn, for the expand window; `null` while there is none. */\n getExpandData() {\n const fig = this._figure;\n if (!fig) return null;\n return {\n title: this.config.title || this.constructor.TITLE,\n // Copies: Plotly writes onto the trace and layout objects it draws.\n traces: fig.traces.map((t) => ({ ...t })),\n layout: { ...(fig.layout || {}) },\n frames: Array.isArray(fig.frames) ? fig.frames : undefined,\n };\n }\n\n // \u2500\u2500 the three states: each one invalidates the figure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n showLoading() {\n this._invalidate();\n super.showLoading();\n }\n\n showEmpty(message) {\n this._invalidate();\n super.showEmpty(message);\n }\n\n showError(message) {\n this._invalidate();\n super.showError(message);\n }\n\n /** Release the figure BEFORE the element goes \u2014 `TileBase.dispose` nulls it. */\n dispose() {\n this._invalidate();\n super.dispose();\n }\n\n /** Any draw in flight is now stale, and the figure on screen is released. */\n _invalidate() {\n this._drawSeq += 1;\n this._releasePlot();\n }\n\n /** Hand the current figure back to Plotly and forget it. Idempotent, and\n * not awaited: a rejected purge (Plotly absent, already purged) must not\n * surface as an unhandled rejection. */\n _releasePlot() {\n const el = this._plotEl;\n this._plotEl = null;\n this._drawn = false;\n this._figure = null;\n if (el) purge(el).catch(() => {});\n }\n\n /**\n * The nodes the content holds while `plotEl` draws `fig`: the plot alone\n * here. A subclass adds what sits around the figure (a note, a caption).\n * @param {HTMLElement} plotEl\n * @param {Object} _fig - what `figure()` answered\n * @returns {HTMLElement[]}\n * @protected\n */\n _figureContent(plotEl, _fig) {\n return [plotEl];\n }\n\n // \u2500\u2500 the draw \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _draw(data) {\n this._drawSeq += 1;\n const seq = this._drawSeq;\n const content = this.contentElement;\n if (!content) return;\n const stale = () => this._disposed || seq !== this._drawSeq;\n\n // Every path below replaces the content, so the figure there now is\n // about to be orphaned whichever way this goes.\n this._releasePlot();\n\n let fig;\n try {\n fig = this.figure(data);\n if (fig != null && (typeof fig !== 'object' || !Array.isArray(fig.traces))) {\n throw new Error('figure() must answer {traces, layout} or null');\n }\n } catch (err) {\n this._failed(err);\n return;\n }\n if (!fig) {\n // A subclass that already said why (showEmpty) has bumped the sequence.\n if (!stale()) this.showEmpty(this.constructor.EMPTY_MESSAGE);\n return;\n }\n\n const host = document.createElement('div');\n host.className = 'fd-figure-tile';\n content.replaceChildren(...this._figureContent(host, fig));\n this._plotEl = host;\n this._drawn = false;\n\n try {\n const P = await ensurePlotly();\n // Data that changed while Plotly was loading: draw only the latest.\n if (stale()) return;\n await createChart(host, fig.traces, fig.layout || {}, { ...FIGURE_CONFIG, ...(fig.config || {}) });\n if (Array.isArray(fig.frames) && fig.frames.length && !stale()) {\n await P.addFrames(host, fig.frames);\n }\n } catch (err) {\n if (stale()) return;\n this._failed(err);\n return;\n }\n if (stale()) {\n // A newer draw or a state change has already replaced the content;\n // this figure is detached, and purging it releases its listeners.\n purge(host).catch(() => {});\n return;\n }\n this._drawn = true;\n this._figure = fig;\n this._wireClick(host);\n }\n\n /** Plotly's click, reduced to the point's own `customdata`. A pie's point\n * carries its slice index as `pointNumber` (older builds: `pointIndex`),\n * and its `customdata` is read off the trace by that index. */\n _wireClick(host) {\n if (typeof host.on !== 'function') return;\n host.on('plotly_click', (ev) => {\n const point = ev?.points?.[0];\n if (!point || typeof this.onPointClick !== 'function') return;\n const trace = point.data || {};\n let customdata = point.customdata;\n if (trace.type === 'pie' || customdata === undefined) {\n const i = point.pointNumber ?? point.pointIndex;\n if (Array.isArray(trace.customdata) && i != null) customdata = trace.customdata[i];\n }\n try {\n this.onPointClick({ customdata, point, tile: this });\n } catch (err) {\n console.error(`[${this.constructor.name}] onPointClick threw:`, err);\n }\n });\n }\n\n async _downloadPng() {\n if (!this._plotEl || !this._drawn) return;\n try {\n const P = await ensurePlotly();\n const uri = await P.toImage(this._plotEl, { format: 'png', scale: 2 });\n const filename = `${slug(this.config.title || this.constructor.TITLE)}.png`;\n // The native Save dialog when the host has one (a desktop window).\n // `saveFile` answers null when there is no dialog behind it, which\n // means \"download it yourself\", not a failed save.\n const dialogs = this.host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: uri.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) this._notify('Download', `Chart saved to ${result.path}`, 'success');\n else if (!result.cancelled) this._notify('Download failed', result.error || 'The image could not be saved', 'error');\n return;\n }\n const a = document.createElement('a');\n a.href = uri;\n a.download = filename;\n a.click();\n } catch (err) {\n this._notify('Download failed', `The image could not be made: ${err?.message || err}`, 'error');\n }\n }\n\n _failed(err) {\n if (this._disposed) return;\n this.showError(`This chart could not be drawn: ${err?.message || err}`);\n this.eventBus?.emit?.('tile:render-failed', {\n tileId: this.id,\n message: err?.message || String(err),\n });\n }\n}\n\nfunction slug(text) {\n return String(text).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'chart';\n}\n\nexport default FigureTile;\n", "/**\n * chart_tiles.js \u2014 a CHART tile and a KPI tile for a `TileGrid`.\n *\n * Lifted from Tables' dashboard widgets (`tables.chart`, `tables.kpi`), with the\n * Tables half left behind: no binding, no Dataset, no column types, no currency\n * refusals. A tile here is handed ALREADY-COMPUTED series through `setData()`;\n * turning records into series is the embedder's job, because only the embedder\n * knows what a record is.\n *\n * import { registerChartTiles } from '@flexdesk/tiles';\n * registerChartTiles(); // idempotent; nothing registers at import\n * const tile = grid.addTile('flexdesk.chart', {x: 0, y: 0, w: 6, h: 4},\n * { chart_type: 'line', title: 'Burndown', unit: 'pts' });\n * tile.setData({\n * series: [\n * { x: days, y: remaining, name: 'Remaining', interpolation: 'step' },\n * { x: days, y: ideal, name: 'Ideal', lineStyle: 'dashed' },\n * ],\n * markers: [{ x: today, label: 'Today' }],\n * note: 'Points from 41 stories',\n * });\n *\n * \u2550\u2550 THE DATA A CHART TILE TAKES \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 * { series: [{x, y, name, color?, lineStyle?, interpolation?, line?, customdata?}],\n * markers?: [{x, label?, color?, lineStyle?}], vertical lines (buildOverlayShapes)\n * referenceLines?: [{value, label?, \u2026}], horizontal lines, passed through\n * xKind?: 'date' | 'number' | 'category', inferred from x when absent\n * note?: string } a line under the figure\n *\n * Shorthands: an ARRAY is `{series: array}`; a single `{x, y}`, `{labels, values}`\n * or `{values}` object is one series. Pie, donut and funnel read `labels`/`values`\n * (or `x`/`y`) of the first series; a histogram reads `values` (or `y`/`x`) of\n * each. `line` on a series is merged over the built `trace.line`, so\n * `line: {shape: 'hv', dash: 'dash'}` is as good as `interpolation`/`lineStyle`.\n *\n * \u2550\u2550 THE DRAW IS FigureTile's \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 * `ChartTile` is a `FigureTile` (figure_tile.js, 0.17.0): it answers\n * `figure(data)` with the traces and layout `_plan` builds, and the base awaits\n * Plotly, draws, discards a stale draw, purges on every state change, relayouts\n * after a resize, downloads the PNG and opens Expand. What stays here is what a\n * CHART is: the data shorthands, the chart types, the note under the figure.\n *\n * The menu is Download PNG alone, as 0.13.0 shipped it: `TileBase`'s two\n * documentation entries belong to an application with documentation.\n */\n\nimport { TileBase } from './tile_base.js';\nimport { FigureTile } from './figure_tile.js';\nimport { registerWidget, getWidget } from './tile_registry.js';\nimport {\n buildTrace, buildXAxisLayout, buildYAxisLayout, buildLegendLayout,\n buildHistogramTrace, buildOverlayShapes,\n} from '../charts/chart_types.js';\nimport { getSeriesColor } from '../charts/plotly_wrapper.js';\nimport { strideDownsampleShared } from '../charts/downsample.js';\n\n/** Part-of-whole types: one series, no axes. */\nconst CATEGORICAL_ONLY = new Set(['pie', 'donut', 'funnel']);\n\n/** Every type the chart tile draws. */\nexport const CHART_TILE_TYPES = Object.freeze([\n { value: 'line', label: 'Line' },\n { value: 'bar', label: 'Bar' },\n { value: 'bar-stacked', label: 'Bar (stacked)' },\n { value: 'bar-horizontal', label: 'Bar (horizontal)' },\n { value: 'area', label: 'Area' },\n { value: 'area-stacked', label: 'Area (stacked %)' },\n { value: 'scatter', label: 'Scatter' },\n { value: 'pie', label: 'Pie' },\n { value: 'donut', label: 'Donut' },\n { value: 'funnel', label: 'Funnel' },\n { value: 'histogram', label: 'Histogram' },\n]);\n\nconst AXIS_CHARTS = ['bar', 'bar-stacked', 'bar-horizontal', 'line', 'area', 'area-stacked', 'scatter'];\n\n/**\n * THE DISPLAY SETTINGS EACH CHART TYPE READS, and the only place that says so:\n * the config schema shows a setting for exactly these types and the draw reads\n * it for no others, so a hidden setting a config still carries cannot go on\n * changing the figure unseen.\n */\nconst READS = Object.freeze({\n legend: new Set([...AXIS_CHARTS, 'pie', 'donut', 'histogram']),\n axis_titles: new Set([...AXIS_CHARTS, 'histogram']),\n y_scale: new Set(['bar', 'bar-horizontal', 'line', 'area', 'scatter']),\n y_range: new Set(['bar', 'bar-stacked', 'bar-horizontal', 'line', 'area', 'scatter']),\n show_markers: new Set(['line', 'area', 'area-stacked']),\n});\n\n/** Room for the tile's own header, and none for a Plotly title never set. */\nconst TILE_MARGIN = { l: 48, r: 16, t: 8, b: 36 };\n\n/** The point count above which a continuous series is decimated \u2014 a rendering\n * budget, not a data limit. */\nconst MAX_POINTS = 2000;\n\n/**\n * Normalise what `setData` was handed into `{series, markers, referenceLines,\n * xKind, note}`, or `null` when there is nothing to draw. Exported for tests\n * and for an embedder that wants to know what the tile will make of its data.\n */\nexport function normalizeChartData(data) {\n if (data == null) return null;\n let d = data;\n if (Array.isArray(d)) d = { series: d };\n else if (typeof d !== 'object') return null;\n else if (!Array.isArray(d.series)) {\n const single = ['x', 'y', 'labels', 'values'].some((k) => Array.isArray(d[k]));\n d = { ...d, series: single ? [d] : [] };\n }\n const series = d.series.filter((s) => s && pointCount(s) > 0);\n if (!series.length) return null;\n return {\n series,\n markers: Array.isArray(d.markers) ? d.markers : [],\n referenceLines: Array.isArray(d.referenceLines) ? d.referenceLines : [],\n xKind: d.xKind || null,\n note: typeof d.note === 'string' ? d.note : '',\n };\n}\n\nfunction pointCount(s) {\n for (const k of ['y', 'values', 'x', 'labels']) {\n if (Array.isArray(s[k])) return s[k].length;\n }\n return 0;\n}\n\nexport class ChartTile extends FigureTile {\n static TYPE = 'flexdesk.chart';\n static TITLE = 'Chart';\n static ICON = 'insert_chart';\n static DESCRIPTION = 'Line, bar, area, pie, donut, funnel or histogram over series you supply.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 3, maxW: 12, maxH: 10 };\n\n /** Pure and static-only \u2014 it runs inside `TileBase`'s constructor. */\n getDefaultConfig() {\n return {\n title: '',\n chart_type: 'line',\n unit: '',\n legend: 'bottom',\n x_title: '',\n y_title: '',\n y_scale: 'linear',\n y_min: null,\n y_max: null,\n show_markers: false,\n max_points: MAX_POINTS,\n };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { key: 'title', type: 'text', label: 'Tile title' },\n { key: 'chart_type', type: 'select', label: 'Chart type',\n options: CHART_TILE_TYPES.map((o) => ({ ...o })) },\n { key: 'unit', type: 'text', label: 'Unit',\n description: 'Shown with the value axis title, e.g. \"pts\" or \"h\".' },\n { key: 'legend', type: 'select', label: 'Legend',\n visibleWhen: { field: 'chart_type', in: [...READS.legend] },\n options: [\n { value: 'bottom', label: 'Below' },\n { value: 'top', label: 'Above' },\n { value: 'right', label: 'Right' },\n { value: 'left', label: 'Left' },\n { value: 'hidden', label: 'None' },\n ] },\n { key: 'x_title', type: 'text', label: 'X axis title',\n visibleWhen: { field: 'chart_type', in: [...READS.axis_titles] } },\n { key: 'y_title', type: 'text', label: 'Y axis title',\n visibleWhen: { field: 'chart_type', in: [...READS.axis_titles] } },\n { key: 'y_scale', type: 'select', label: 'Y scale',\n visibleWhen: { field: 'chart_type', in: [...READS.y_scale] },\n options: [{ value: 'linear', label: 'Linear' }, { value: 'log', label: 'Logarithmic' }] },\n { key: 'y_min', type: 'number', label: 'Y minimum',\n visibleWhen: { field: 'chart_type', in: [...READS.y_range] } },\n { key: 'y_max', type: 'number', label: 'Y maximum',\n visibleWhen: { field: 'chart_type', in: [...READS.y_range] } },\n { key: 'show_markers', type: 'checkbox', label: 'Show point markers',\n visibleWhen: { field: 'chart_type', in: [...READS.show_markers] } },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n }\n\n /**\n * `null` here is \"the grid has no data\", not \"clear this tile\": TileGrid's\n * config save calls `update(grid.data, newConfig)`, and a grid whose tiles\n * are fed one by one through `setData` has `grid.data === null` \u2014 passed on,\n * it would drop the tile's series and skip the redraw in the new chart type.\n * `setData(null)` is how a tile is cleared.\n */\n update(data, config) {\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n }\n\n /** `null` (the empty state) when there is nothing to draw. */\n figure(data) {\n const norm = normalizeChartData(data);\n if (!norm) return null;\n return { ...this._plan(norm), note: norm.note };\n }\n\n /** Download PNG alone \u2014 see the header. */\n menuItems() {\n return this._figureMenuItems();\n }\n\n /** The figure, and the note on its own line under it. */\n _figureContent(plotEl, fig) {\n plotEl.classList.add('fd-chart-tile');\n if (!fig.note) return [plotEl];\n const note = document.createElement('div');\n note.className = 'fd-chart-tile__note';\n note.setAttribute('role', 'note');\n note.textContent = fig.note;\n note.title = fig.note;\n return [plotEl, note];\n }\n\n /** Turn normalised data into `{traces, layout}`. */\n _plan(norm) {\n const type = this.config.chart_type || 'line';\n const { series } = norm;\n\n if (CATEGORICAL_ONLY.has(type)) {\n // ONE series. A pie of three is three pies drawn on top of one another.\n const s = series[0];\n const labels = s.labels ?? s.x ?? [];\n const values = s.values ?? s.y ?? [];\n const trace = buildTrace({\n chartType: type,\n x: labels.map((v) => (v === null || v === undefined ? '\u2014' : String(v))),\n y: values,\n name: s.name || '',\n colors: s.colors || null,\n });\n if (Array.isArray(s.customdata)) trace.customdata = s.customdata;\n return {\n traces: [trace],\n layout: {\n margin: type === 'funnel' ? { ...TILE_MARGIN, l: 96 } : TILE_MARGIN,\n ...this._legend(),\n },\n };\n }\n\n if (type === 'histogram') {\n const traces = series.map((s, i) => {\n const raw = s.values ?? s.y ?? s.x ?? [];\n const trace = {\n ...buildHistogramTrace({\n x: raw.map(toNumber).filter((v) => v !== null),\n color: s.color || getSeriesColor(i),\n name: s.name || `Series ${i + 1}`,\n ...(s.nbins ? { nbins: s.nbins } : {}),\n }),\n opacity: series.length > 1 ? 0.7 : 1,\n };\n return trace;\n });\n return {\n traces,\n layout: {\n margin: TILE_MARGIN, ...this._legend(), barmode: 'overlay',\n xaxis: buildXAxisLayout({ title: this.config.x_title || '' }),\n yaxis: buildYAxisLayout({ axisId: 'yaxis', title: this.config.y_title || 'Count' }),\n },\n };\n }\n\n const kind = norm.xKind || inferXKind(series);\n const base = type.startsWith('bar') ? 'bar' : type;\n const target = Number(this.config.max_points) || MAX_POINTS;\n const showMarkers = READS.show_markers.has(type) && this.config.show_markers === true;\n\n const traces = series.map((s, i) => {\n let x = Array.isArray(s.x) ? s.x : (s.y || []).map((_, j) => j);\n let y = Array.isArray(s.y) ? s.y : (s.values || []);\n let customdata = Array.isArray(s.customdata) ? s.customdata : null;\n if (kind !== 'category') {\n const cut = strideDownsampleShared(x, customdata ? { y, customdata } : { y }, target);\n x = cut.time;\n y = cut.series.y;\n if (customdata) customdata = cut.series.customdata;\n }\n const trace = buildTrace({\n chartType: base,\n x,\n y,\n name: s.name || `Series ${i + 1}`,\n color: s.color || null,\n lineStyle: s.lineStyle || 'solid',\n interpolation: s.interpolation || 'linear',\n ...(s.lineWidth ? { lineWidth: s.lineWidth } : {}),\n seriesIndex: i,\n showMarkers,\n });\n if (s.line && typeof s.line === 'object') trace.line = { ...(trace.line || {}), ...s.line };\n if (customdata) trace.customdata = customdata;\n return trace;\n });\n\n const xaxis = buildXAxisLayout({ title: this.config.x_title || '', scaleType: 'linear' });\n if (kind !== 'number') xaxis.type = kind === 'date' ? 'date' : 'category';\n\n const log = READS.y_scale.has(type) && this.config.y_scale === 'log';\n const yaxis = buildYAxisLayout({\n axisId: 'yaxis',\n title: this._valueTitle(series),\n scaleType: log ? 'log' : 'linear',\n min: READS.y_range.has(type) ? axisBound(this.config.y_min, log) : null,\n max: READS.y_range.has(type) ? axisBound(this.config.y_max, log) : null,\n });\n\n const layout = { margin: TILE_MARGIN, xaxis, yaxis, ...this._legend() };\n if (type === 'bar') layout.barmode = 'group';\n if (type === 'bar-stacked') layout.barmode = 'stack';\n if (type === 'bar-horizontal') {\n // Swap the DATA and the AXES together; swapping one draws NaN.\n layout.barmode = 'group';\n for (const t of traces) { [t.x, t.y] = [t.y, t.x]; t.orientation = 'h'; }\n [layout.xaxis, layout.yaxis] = [yaxis, xaxis];\n layout.margin = { ...TILE_MARGIN, l: 96 };\n }\n\n const overlay = buildOverlayShapes({\n verticalLines: type === 'bar-horizontal' ? [] : norm.markers,\n referenceLines: norm.referenceLines,\n });\n if (overlay.shapes.length) layout.shapes = overlay.shapes;\n if (overlay.annotations.length) layout.annotations = overlay.annotations;\n return { traces, layout };\n }\n\n /** The value axis title: the configured one, else the single series' name,\n * with the unit beside it. */\n _valueTitle(series) {\n const unit = (this.config.unit || '').trim();\n const base = this.config.y_title || (series.length === 1 ? (series[0].name || '') : '');\n if (!unit) return base;\n return base ? `${base} (${unit})` : unit;\n }\n\n /**\n * `showlegend` and `legend`, lifted out by name: `buildLegendLayout`'s\n * top-level `font` would replace the theme's whole font object. Below the\n * plot it is anchored to the CONTAINER, so the axis title sits above it\n * however tall the tick labels are.\n */\n _legend() {\n if (!READS.legend.has(this.config.chart_type || 'line')) return { showlegend: false };\n const position = this.config.legend || 'bottom';\n const spec = buildLegendLayout(position);\n const out = { showlegend: spec.showlegend === true };\n if (spec.legend) out.legend = spec.legend;\n if (position === 'bottom' && out.legend) {\n out.legend = { ...out.legend, yref: 'container', y: 0, yanchor: 'bottom' };\n }\n return out;\n }\n}\n\n/**\n * ONE NUMBER, AND WHAT IT IS DOING. Plain DOM, no Plotly: a KPI strip is the\n * common board, and it should not pay 4 MB for three divs \u2014 nor wait for them.\n * It therefore renders synchronously and renders without Plotly loaded at all.\n *\n * tile.setData({ value: 42, reference: 37, label: 'Open bugs', note: 'vs last week' })\n *\n * A bare number is `{value}`. The delta's ARROW states the fact (up or down);\n * `invert_delta` flips only the colour's judgement, so a falling cost is a\n * green \u25BC. The sign is in the text too, because colour alone does not survive\n * a monochrome display.\n */\nexport class KpiTile extends TileBase {\n static TYPE = 'flexdesk.kpi';\n static TITLE = 'KPI';\n static ICON = 'speed';\n static DESCRIPTION = 'One number with a label and an optional comparison.';\n static DEFAULT_SIZE = { w: 3, h: 2 };\n static SIZE_CONSTRAINTS = { minW: 2, minH: 2, maxW: 12, maxH: 6 };\n\n getDefaultConfig() {\n return {\n title: '',\n label: '',\n unit: '',\n format: 'number',\n decimals: null,\n prefix: '',\n suffix: '',\n currency: null,\n delta_relative: false,\n invert_delta: false,\n foot: '',\n };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { key: 'title', type: 'text', label: 'Tile title' },\n { key: 'label', type: 'text', label: 'Label' },\n { key: 'unit', type: 'text', label: 'Unit', description: 'Shown after the number, e.g. \"pts\".' },\n { key: 'format', type: 'select', label: 'Format',\n options: [\n { value: 'number', label: 'Number' },\n { value: 'percent', label: 'Percentage (of a ratio)' },\n { value: 'currency', label: 'Currency' },\n { value: 'duration', label: 'Duration (seconds)' },\n { value: 'text', label: 'Text' },\n ] },\n { key: 'decimals', type: 'number', label: 'Decimals', min: 0, max: 6 },\n { key: 'currency', type: 'text', label: 'Currency code',\n description: 'ISO 4217, e.g. EUR. Left empty, the number is shown without a symbol.' },\n { key: 'prefix', type: 'text', label: 'Prefix' },\n { key: 'suffix', type: 'text', label: 'Suffix' },\n { key: 'delta_relative', type: 'checkbox', label: 'Show the change as a percentage' },\n { key: 'invert_delta', type: 'checkbox', label: 'A fall is good',\n description: 'For a cost, a queue length or a latency: a smaller number is the better one.' },\n { key: 'foot', type: 'text', label: 'Caption' },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n }\n\n /** `null` is \"the grid has no data\" \u2014 see `ChartTile.update`. And a value of\n * `0` is a value: `TileBase.update` re-renders truthy data only. */\n update(data, config) {\n if (this._disposed) return;\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n const d = this.data;\n if (d !== null && d !== undefined && !d && this.contentElement) this.render(d);\n }\n\n /** `{value, reference?, label?, note?}` or a bare number; null is the empty state. */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n render(data) {\n const content = this.contentElement;\n if (!content) return;\n const d = typeof data === 'number' ? { value: data } : data;\n if (!d || typeof d !== 'object' || d.value === null || d.value === undefined || d.value === '') {\n this.showEmpty('No value to show.');\n return;\n }\n\n content.replaceChildren();\n const box = document.createElement('div');\n box.className = 'fd-kpi';\n\n const labelText = d.label || this.config.label || '';\n if (labelText) {\n const label = document.createElement('div');\n label.className = 'fd-kpi__label';\n label.textContent = labelText;\n label.title = labelText;\n box.append(label);\n }\n\n const big = document.createElement('div');\n big.className = 'fd-kpi__value';\n big.textContent = this._format(d.value, true);\n big.title = String(d.value);\n box.append(big);\n\n const delta = this._buildDelta(d.value, d.reference);\n if (delta) box.append(delta);\n\n const foot = [this.config.foot, d.note].filter(Boolean).join(' \u00B7 ');\n if (foot) {\n const el = document.createElement('div');\n el.className = 'fd-kpi__foot';\n el.textContent = foot;\n el.title = foot;\n box.append(el);\n }\n content.append(box);\n }\n\n /** The comparison line, or `null` when there is nothing to compare against.\n * `0` is a real reference \u2014 the test is finiteness, never truthiness. */\n _buildDelta(rawValue, rawReference) {\n const value = Number(rawValue);\n if (rawReference === null || rawReference === undefined || rawReference === '') return null;\n const reference = Number(rawReference);\n if (!Number.isFinite(value) || !Number.isFinite(reference)) return null;\n\n const change = value - reference;\n const el = document.createElement('div');\n el.className = 'fd-kpi__delta';\n // No change gets neither colour: a flat week is not a good one.\n if (change > 0) el.classList.add(this.config.invert_delta ? 'fd-kpi__delta--down' : 'fd-kpi__delta--up');\n else if (change < 0) el.classList.add(this.config.invert_delta ? 'fd-kpi__delta--up' : 'fd-kpi__delta--down');\n\n const arrow = change > 0 ? '\u25B2' : change < 0 ? '\u25BC' : '\u2013';\n const magnitude = this.config.delta_relative\n ? (reference === 0 ? null : formatValue(Math.abs(change / reference), {\n format: 'percent', decimals: this.config.decimals ?? 1 }))\n : this._format(Math.abs(change), false);\n const sign = change > 0 ? '+' : change < 0 ? '-' : '';\n el.textContent = magnitude === null ? `${arrow} \u2014` : `${arrow} ${sign}${magnitude}`;\n el.title = `Compared with ${this._format(reference, false)}`;\n return el;\n }\n\n _format(value, withAffixes) {\n const format = this.config.format || 'number';\n const body = formatValue(value, {\n format: format === 'text' && !withAffixes ? 'number' : format,\n decimals: this.config.decimals,\n currency: this.config.currency,\n prefix: withAffixes ? this.config.prefix : '',\n suffix: withAffixes ? this.config.suffix : '',\n });\n const unit = (this.config.unit || '').trim();\n return unit && body !== '\u2014' ? `${body} ${unit}` : body;\n }\n}\n\n/**\n * Register both tiles. Idempotent: a second call registers nothing new and\n * replaces nothing \u2014 and nothing registers at import time, so an app that\n * imports `@flexdesk/tiles` without wanting these never sees them in its\n * Add-widget catalogue.\n */\nexport function registerChartTiles() {\n for (const Tile of [ChartTile, KpiTile]) {\n if (getWidget(Tile.TYPE) !== Tile) registerWidget(Tile);\n }\n}\n\n// \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\u2500\u2500\u2500\u2500\u2500\n\n/** The header shows `config.title`, else the type's own title. */\nfunction applyTitle(tile) {\n tile.setTitle(tile.config.title || tile.constructor.TITLE);\n}\n\n/** `'date' | 'number' | 'category'` from the x values themselves. */\nfunction inferXKind(series) {\n let sawAny = false;\n let allNumbers = true;\n let allDates = true;\n for (const s of series) {\n for (const v of (Array.isArray(s.x) ? s.x : [])) {\n if (v === null || v === undefined) continue;\n sawAny = true;\n if (typeof v !== 'number') allNumbers = false;\n if (!(v instanceof Date) && !(typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2}/.test(v))) allDates = false;\n if (!allNumbers && !allDates) return 'category';\n }\n }\n if (!sawAny || allNumbers) return 'number';\n return allDates ? 'date' : 'category';\n}\n\n/** A value as a number, or `null` \u2014 never `NaN`. */\nfunction toNumber(value) {\n if (value === null || value === undefined || value === '') return null;\n const n = Number(value);\n return Number.isFinite(n) ? n : null;\n}\n\n/** A Y bound as the axis reads it: on a log axis Plotly reads `range` in log\u2081\u2080\n * units, and a non-positive bound has no place there at all. */\nfunction axisBound(value, log) {\n const n = toNumber(value);\n if (n === null || !log) return n;\n return n > 0 ? Math.log10(n) : null;\n}\n\nfunction fractionDigits(decimals) {\n const d = Math.max(0, Math.min(20, Number(decimals) || 0));\n return { minimumFractionDigits: d, maximumFractionDigits: d };\n}\n\n/** Seconds as `1d 4h`, `4h 12m`, `12m 30s`, `30s` \u2014 two units, never three. */\nfunction formatDuration(seconds) {\n if (!Number.isFinite(seconds)) return '\u2014';\n const sign = seconds < 0 ? '-' : '';\n let rest = Math.abs(Math.round(seconds));\n const days = Math.floor(rest / 86400); rest -= days * 86400;\n const hours = Math.floor(rest / 3600); rest -= hours * 3600;\n const minutes = Math.floor(rest / 60);\n const secs = rest - minutes * 60;\n if (days) return `${sign}${days}d ${hours}h`;\n if (hours) return `${sign}${hours}h ${minutes}m`;\n if (minutes) return `${sign}${minutes}m ${secs}s`;\n return `${sign}${secs}s`;\n}\n\n/**\n * The KPI's formatter. `currency` has NO default: a symbol nobody chose is a\n * claim about money that may be false. `percent` takes a RATIO (0.42 \u2192 42%).\n */\nfunction formatValue(value, { format = 'number', decimals = null, prefix = '', suffix = '',\n currency = null } = {}) {\n if (value === null || value === undefined || value === '') return '\u2014';\n const n = Number(value);\n const body = (() => {\n switch (format) {\n case 'number':\n if (!Number.isFinite(n)) return String(value);\n return decimals === null || decimals === undefined\n ? n.toLocaleString()\n : n.toLocaleString(undefined, fractionDigits(decimals));\n case 'percent':\n if (!Number.isFinite(n)) return String(value);\n return `${(n * 100).toLocaleString(undefined, fractionDigits(decimals ?? 1))}%`;\n case 'currency':\n if (!Number.isFinite(n)) return String(value);\n if (!currency) return n.toLocaleString(undefined, fractionDigits(decimals ?? 2));\n try {\n return n.toLocaleString(undefined, { style: 'currency', currency, ...fractionDigits(decimals ?? 2) });\n } catch {\n // An unknown code throws a RangeError from inside a render.\n return n.toLocaleString(undefined, fractionDigits(decimals ?? 2));\n }\n case 'duration':\n return formatDuration(n);\n default:\n return String(value);\n }\n })();\n return `${prefix || ''}${body}${suffix || ''}`;\n}\n", "/**\n * layout_persistence.js \u2014 saved tile layouts, keyed by whatever the app keys them by.\n *\n * Three things used to make this un-shippable, and all three are now injected:\n *\n * 1. It wrote to `localStorage` under two keys named after one application\n * \u2014 a LIBRARY scribbling on one application's storage\n * keys. The keys are the consumer's now, and EcoAgent passes its existing ones,\n * so not a single saved layout is orphaned.\n *\n * 2. It imported EcoAgent's TemplateRegistry to pick a starting layout. That is a\n * `resolveTemplate` callback now: hand it your context, get a layout back, or\n * return null and get an empty grid.\n *\n * 3. Everything was called `scenarioId`, 85 times. A tile layout is keyed by\n * SOMETHING \u2014 a scenario, a document, a user, a run \u2014 and the library does not\n * get an opinion about which. It is `contextId` now. This is a rename of\n * IDENTIFIERS only: the old name was never a stored string, just a key into the\n * stored object, so no persisted data changes shape.\n *\n * `storage` is any synchronous Storage-shaped object (getItem/setItem/removeItem).\n * It defaults to localStorage because that is what a browser has; it is not the Host,\n * because the Host is async and every caller of this class is not.\n */\n\nconst LAYOUT_VERSION = 3;\n\nconst DEFAULT_LAYOUTS_KEY = 'twm.tiles.layouts';\nconst DEFAULT_CONFIGS_KEY = 'twm.tiles.configs';\n\nexport class LayoutPersistence {\n constructor({\n storage = (typeof localStorage !== 'undefined' ? localStorage : null),\n layoutsKey = DEFAULT_LAYOUTS_KEY,\n configsKey = DEFAULT_CONFIGS_KEY,\n resolveTemplate = null,\n logger = null,\n } = {}) {\n this._cache = null;\n this._storage = storage;\n this._logger = logger;\n this._layoutsKey = layoutsKey;\n this._configsKey = configsKey;\n // (context) => layout | null. No resolver => no starting template.\n this._resolveTemplate = typeof resolveTemplate === 'function' ? resolveTemplate : null;\n }\n\n /**\n * Get layout for a specific context.\n * Falls back to template resolution when no saved layout exists.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} Layout object with tiles array\n */\n getLayout(contextId, context) {\n const all = this._loadAll();\n const layout = all[contextId];\n\n if (layout && layout.version === LAYOUT_VERSION) {\n return layout;\n }\n\n // Resolve a template based on context metadata\n const instantiated = this._resolveTemplate?.(context) ?? null;\n if (instantiated) {\n return {\n tiles: instantiated.tiles,\n version: LAYOUT_VERSION,\n templateId: instantiated.templateId,\n templateModified: false,\n };\n }\n\n // Final fallback: empty layout (should not happen \u2014 resolve always returns a default)\n return { tiles: [], version: LAYOUT_VERSION };\n }\n\n /**\n * Save layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n saveLayout(contextId, layout) {\n const all = this._loadAll();\n\n // Handle both array (from TileGrid.getLayout) and object (with tiles property) formats\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId] = {\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n updatedAt: Date.now(),\n templateId: layout?.templateId || all[contextId]?.templateId || null,\n templateModified: layout?.templateModified ?? true,\n };\n\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Saved layout for context ${contextId}`);\n }\n\n /**\n * Delete layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n */\n deleteLayout(contextId) {\n const all = this._loadAll();\n\n if (all[contextId]) {\n delete all[contextId];\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted layout for context ${contextId}`);\n }\n }\n\n /**\n * Reset a layout by re-resolving the best-matching template.\n *\n * With no `resolveTemplate` supplied, \"reset\" means \"empty grid\" \u2014 which is the\n * honest answer for a library that has no templates. The previous code called\n * `TemplateRegistry.instantiate()` unconditionally and read `.tiles` off the\n * result, so a null resolver here would have been a TypeError.\n *\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} The resolved layout (empty if nothing resolves).\n */\n resetLayout(contextId, context) {\n const instantiated = this._resolveTemplate?.(context) ?? null;\n const layout = {\n tiles: instantiated?.tiles ?? [],\n version: LAYOUT_VERSION,\n templateId: instantiated?.templateId ?? null,\n templateModified: false,\n };\n this.saveLayout(contextId, layout);\n return layout;\n }\n\n /**\n * Check if a context has a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n hasLayout(contextId) {\n const all = this._loadAll();\n return !!all[contextId];\n }\n\n /**\n * Get all context IDs with saved layouts.\n * @returns {Array<string>}\n */\n getAllContextIds() {\n const all = this._loadAll();\n return Object.keys(all);\n }\n\n /**\n * Export all layouts as JSON string.\n * @returns {string}\n */\n exportAll() {\n const all = this._loadAll();\n return JSON.stringify(all, null, 2);\n }\n\n /**\n * Import layouts from JSON string.\n * @param {string} json - JSON string of layouts\n * @param {boolean} [merge=false] - Whether to merge with existing or replace\n */\n importAll(json, merge = false) {\n try {\n const imported = JSON.parse(json);\n\n if (merge) {\n const existing = this._loadAll();\n this._saveAll({ ...existing, ...imported });\n } else {\n this._saveAll(imported);\n }\n\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Imported layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to import layouts:', err);\n }\n }\n\n /**\n * Clear all saved layouts.\n */\n clearAll() {\n try {\n this._storage?.removeItem(this._layoutsKey);\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Cleared all layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to clear layouts:', err);\n }\n }\n\n /**\n * Load all layouts from storage.\n * @returns {Object}\n * @private\n */\n _loadAll() {\n if (this._cache) {\n return this._cache;\n }\n\n try {\n const raw = this._storage?.getItem(this._layoutsKey);\n if (raw) {\n this._cache = JSON.parse(raw);\n return this._cache;\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load layouts:', err);\n }\n\n this._cache = {};\n return this._cache;\n }\n\n /**\n * Save all layouts to storage.\n * @param {Object} data\n * @private\n */\n _saveAll(data) {\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save layouts:', err);\n\n // If quota exceeded, try to clear old entries\n if (err.name === 'QuotaExceededError') {\n this._pruneOldLayouts(data);\n }\n }\n }\n\n /**\n * Remove oldest layouts to free up space.\n * @param {Object} data\n * @private\n */\n _pruneOldLayouts(data) {\n const entries = Object.entries(data);\n\n // Sort by updatedAt, oldest first\n entries.sort((a, b) => (a[1].updatedAt || 0) - (b[1].updatedAt || 0));\n\n // Remove oldest 25%\n const removeCount = Math.ceil(entries.length * 0.25);\n for (let i = 0; i < removeCount; i++) {\n delete data[entries[i][0]];\n }\n\n // Try saving again\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n this._logger?.warn?.('[LayoutPersistence] Pruned old layouts due to quota');\n } catch (err) {\n console.error('[LayoutPersistence] Still cannot save after pruning:', err);\n }\n }\n\n /**\n * Get the template ID associated with a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {string|null} Template ID or null\n */\n getTemplateId(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateId || null;\n }\n\n /**\n * Check if the user has modified the layout since the template was applied.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n isTemplateModified(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateModified ?? false;\n }\n\n // =========================================================================\n // NAMED CONFIGURATION MANAGEMENT\n // =========================================================================\n\n /**\n * Get all saved configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object} { activeId: string, configs: { id: { name, tiles, createdAt } } }\n */\n getConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (contextConfigs && Object.keys(contextConfigs.configs || {}).length > 0) {\n return contextConfigs;\n }\n\n // Return empty structure\n return {\n activeId: null,\n configs: {}\n };\n }\n\n /**\n * Save the current layout as a named configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} name - Configuration name\n * @param {Array|Object} layout - Layout to save\n * @param {Object} [options] - Additional options\n * @param {string} [options.templateId] - Template ID that generated this layout\n * @returns {string} The new configuration ID\n */\n saveConfiguration(contextId, name, layout, options) {\n const all = this._loadConfigs();\n\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n\n // Ensure unique name\n const uniqueName = this._getUniqueName(all[contextId].configs, name);\n\n const configId = `config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId] = {\n name: uniqueName,\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n createdAt: Date.now(),\n templateId: options?.templateId || null,\n };\n\n // Set as active if it's the first one\n if (!all[contextId].activeId) {\n all[contextId].activeId = configId;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Saved configuration \"${uniqueName}\" for context ${contextId}`);\n\n return configId;\n }\n\n /**\n * Generate a unique name by appending (2), (3), etc. if name already exists.\n * @param {Object} configs - Existing configurations object\n * @param {string} name - Desired name\n * @returns {string} Unique name\n * @private\n */\n _getUniqueName(configs, name) {\n if (!configs) return name;\n\n const existingNames = new Set(Object.values(configs).map(c => c.name));\n\n if (!existingNames.has(name)) {\n return name;\n }\n\n // Find next available number\n let counter = 2;\n let candidate = `${name} (${counter})`;\n while (existingNames.has(candidate)) {\n counter++;\n candidate = `${name} (${counter})`;\n }\n\n return candidate;\n }\n\n /**\n * Load a specific configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {Object|null} Configuration layout or null if not found\n */\n loadConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n const config = all[contextId]?.configs?.[configId];\n\n if (config) {\n // Update active config\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n return config;\n }\n\n return null;\n }\n\n /**\n * Delete a saved configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {boolean} True if deleted, false if not found\n */\n deleteConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n delete all[contextId].configs[configId];\n\n // Update active if deleted\n if (all[contextId].activeId === configId) {\n const remaining = Object.keys(all[contextId].configs);\n all[contextId].activeId = remaining.length > 0 ? remaining[0] : null;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted configuration ${configId} for context ${contextId}`);\n\n return true;\n }\n\n /**\n * Update an existing configuration's layout (without creating a new ID).\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {Array|Object} layout - New layout to save\n * @returns {boolean} True if updated, false if not found\n */\n updateConfiguration(contextId, configId, layout) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId].tiles = tilesArray;\n all[contextId].configs[configId].version = LAYOUT_VERSION;\n all[contextId].configs[configId].updatedAt = Date.now();\n\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Update the templateId on an existing configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} templateId - New template ID\n * @returns {boolean} True if updated, false if not found\n */\n updateConfigurationTemplateId(contextId, configId, templateId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n all[contextId].configs[configId].templateId = templateId;\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Rename a configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} newName - New name\n * @returns {string|false} The actual name used (may differ if duplicate), or false if not found\n */\n renameConfiguration(contextId, configId, newName) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n // Get configs excluding the one being renamed for uniqueness check\n const otherConfigs = {};\n Object.entries(all[contextId].configs).forEach(([id, config]) => {\n if (id !== configId) {\n otherConfigs[id] = config;\n }\n });\n\n const uniqueName = this._getUniqueName(otherConfigs, newName);\n all[contextId].configs[configId].name = uniqueName;\n this._saveConfigs(all);\n\n return uniqueName;\n }\n\n /**\n * Get the active configuration for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object|null} { id, name, tiles } or null\n */\n getActiveConfiguration(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.activeId) {\n return null;\n }\n\n const activeConfig = contextConfigs.configs[contextConfigs.activeId];\n if (activeConfig) {\n return {\n id: contextConfigs.activeId,\n ...activeConfig\n };\n }\n\n return null;\n }\n\n /**\n * Set the active configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n */\n setActiveConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (all[contextId]?.configs?.[configId]) {\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n }\n }\n\n /**\n * List all configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Array} Array of { id, name, createdAt, isActive }\n */\n listConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.configs) {\n return [];\n }\n\n return Object.entries(contextConfigs.configs).map(([id, config]) => ({\n id,\n name: config.name,\n createdAt: config.createdAt,\n isActive: id === contextConfigs.activeId\n })).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n }\n\n /**\n * Get the template set fingerprint for a context.\n * Used to detect when templates have changed and configs need regeneration.\n * @param {string} contextId\n * @returns {string|null}\n */\n getTemplateSetId(contextId) {\n const all = this._loadConfigs();\n return all[contextId]?.templateSetId || null;\n }\n\n /**\n * Store the template set fingerprint for a context.\n * @param {string} contextId\n * @param {string} templateSetId\n */\n setTemplateSetId(contextId, templateSetId) {\n const all = this._loadConfigs();\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n all[contextId].templateSetId = templateSetId;\n this._saveConfigs(all);\n }\n\n /**\n * Delete ALL configurations for a context.\n * @param {string} contextId\n */\n clearConfigurations(contextId) {\n const all = this._loadConfigs();\n delete all[contextId];\n this._saveConfigs(all);\n }\n\n /**\n * Load all configurations from storage.\n * @returns {Object}\n * @private\n */\n _loadConfigs() {\n try {\n const raw = this._storage?.getItem(this._configsKey);\n if (raw) {\n return JSON.parse(raw);\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load configurations:', err);\n }\n return {};\n }\n\n /**\n * Save all configurations to storage.\n * @param {Object} data\n * @private\n */\n _saveConfigs(data) {\n try {\n this._storage?.setItem(this._configsKey, JSON.stringify(data));\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save configurations:', err);\n }\n }\n}\n\n// Singleton instance\nlet instance = null;\nlet _options = {};\n\n/**\n * Configure the singleton BEFORE anything reads it. Call once, at boot.\n *\n * The first cut let `getLayoutPersistence(options)` configure it lazily \u2014 whoever\n * called first won. That is a trap with teeth: if ANY code path had reached the\n * store before the dashboard did, the singleton would have been built with the\n * library's generic defaults, and the app would have read\n * 'twm.tiles.layouts' instead of the app's own key \u2014 an empty store. Every\n * saved dashboard a user had ever built would have silently vanished, with no\n * error, and no captured view would show it because the pixel gate runs on a\n * fresh template that has no saved layouts to lose.\n *\n * Configure once, at boot, where the ordering is not in question.\n */\nexport function configureLayoutPersistence(options = {}) {\n _options = options;\n instance = null; // rebuild on next get\n}\n\n/** @returns {LayoutPersistence} */\nexport function getLayoutPersistence() {\n if (!instance) {\n instance = new LayoutPersistence(_options);\n }\n return instance;\n}\n\nexport default LayoutPersistence;\n", "/**\n * list_tiles.js \u2014 a LIST tile and a PEOPLE tile for a `TileGrid` (0.16.1).\n *\n * Both are rows you hand over through `setData()`, the way the chart tile takes\n * series: which records are in the list, how they sort and what a row says is\n * the embedder's job, because only the embedder knows what a record is. What a\n * tile here owns is everything a list on a board needs and every embedder would\n * otherwise write again: the count, the empty line, the \"open all of these\"\n * button, a click, the keyboard, and a right-click menu per row.\n *\n * import { registerListTiles } from '@flexdesk/tiles';\n * registerListTiles(); // idempotent; nothing registers at import\n * const tile = grid.addTile('flexdesk.list', {x: 0, y: 0, w: 6, h: 4},\n * { title: 'Overdue', empty_text: 'Nothing is late.' });\n * tile.onRowActivate = ({ row, event }) => open(row.key, event.ctrlKey);\n * tile.rowMenu = ({ row }) => [{ label: 'Open', icon: 'open_in_new', action: 'open' }];\n * tile.onRowMenuAction = ({ action, row }) => { \u2026 };\n * tile.setData({\n * rows: [{ key: '7', icon: 'task', lead: 'TASK-0007', title: 'Sign-off',\n * cells: [{ text: 'priya' }, { text: '9 days late', tone: 'danger' }] }],\n * total: 12, // \"7 of 12\" when only 7 are handed over\n * action: { label: 'Open as a list' }, // the button in the bar; see onAction\n * });\n *\n * \u2550\u2550 THE DATA \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 * list { rows: [Row], total?, note?, empty?, action?: {label, icon?} } (an array is {rows})\n * Row = { key, title, icon?, iconTitle?, lead?, className?, tip?,\n * cells?: [{ text, title?, tone?, icon?, className? }] }\n * people { people: [Person], total?, note?, empty?, action? } (an array is {people})\n * Person = { key, name, icon?, muted?, count, countLabel?, title?,\n * pills?: [{ text, tone?, title? }] }\n *\n * `tone` is one of `danger`, `warning`, `ok`, `muted` and only picks a colour;\n * the text says the same thing, because colour alone does not survive a\n * monochrome display. `className` is the embedder's own class, added as it is,\n * so a status pill can keep the app's look.\n *\n * AN EMPTY LIST IS NOT THE EMPTY STATE. `{rows: []}` keeps the bar (count 0,\n * the button) and says `empty` (or `config.empty_text`) where the rows would be:\n * \"nothing is late\" is the most useful thing a list of late work can say, and a\n * tile that shows a grey inbox icon instead cannot say it. `setData(null)` is\n * the empty state; `showEmpty(message)` is how an embedder says \"not set up\".\n *\n * \u2550\u2550 INPUT \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 * A row is `role=\"button\"` with a tab stop. Click, Enter and Space call\n * `onRowActivate({row, event, tile})` with the event, so the modifier keys\n * decide how it opens. Up and Down move between rows, Home and End to the ends.\n * Right-click, the context-menu key and Shift+F10 open the row's menu:\n * `rowMenu({row, event, tile})` answers the items (`showContextMenu`'s; none or\n * `[]` means no menu, and the browser's own is left alone) and the choice goes\n * to `onRowMenuAction({action, row, tile})`. The bar's button calls\n * `onAction({tile, event})`. Every hook can also be passed to the constructor.\n * A row carries `data-row-key`, so an embedder can find it for its own\n * listeners (a drag source, say); `rowsDraggable` makes rows `draggable`.\n *\n * The header reads `config.title`, else the type's title; the count is in the\n * bar, not the header, so a title the embedder sets is never rewritten.\n */\n\nimport { TileBase } from './tile_base.js';\nimport { registerWidget, getWidget } from './tile_registry.js';\nimport { showContextMenu } from '../ui/components/context_menu.js';\n\nconst TONES = new Set(['danger', 'warning', 'ok', 'muted']);\n\n/** `{items, total, note, empty, action}` from what `setData` was handed under\n * `key` (`rows` or `people`), or null when there is nothing at all. */\nfunction normalize(data, key) {\n if (data == null) return null;\n const d = Array.isArray(data) ? { [key]: data } : data;\n if (typeof d !== 'object' || !Array.isArray(d[key])) return null;\n const items = d[key].filter((r) => r && typeof r === 'object' && r.key != null);\n const total = Number.isFinite(Number(d.total)) && d.total !== null && d.total !== '' ? Number(d.total) : items.length;\n return {\n items,\n total: Math.max(total, items.length),\n note: typeof d.note === 'string' ? d.note : '',\n empty: typeof d.empty === 'string' ? d.empty : '',\n action: d.action && typeof d.action === 'object' && d.action.label ? d.action : null,\n };\n}\n\n/** Exported for tests and for an embedder that wants to know what the tile will make of its data. */\nexport const normalizeListData = (data) => normalize(data, 'rows');\nexport const normalizePeopleData = (data) => normalize(data, 'people');\n\nfunction el(tag, cls, text) {\n const e = document.createElement(tag);\n if (cls) e.className = cls;\n if (text != null) e.textContent = String(text);\n return e;\n}\n\nfunction glyph(name, cls = '') {\n const g = el('span', `material-symbols-outlined${cls ? ` ${cls}` : ''}`, name);\n g.setAttribute('aria-hidden', 'true');\n return g;\n}\n\nconst toneClass = (base, tone) => (TONES.has(tone) ? ` ${base}--${tone}` : '');\n\n/**\n * The rows, the bar and the input, shared by both tiles. A subclass says what\n * its items are called in the data (`_KEY`) and draws one (`_renderItem`).\n * @abstract\n */\nclass RowsTile extends TileBase {\n static _KEY = 'rows';\n\n constructor(options = {}) {\n super(options);\n this.onRowActivate = typeof options.onRowActivate === 'function' ? options.onRowActivate : null;\n this.rowMenu = typeof options.rowMenu === 'function' ? options.rowMenu : null;\n this.onRowMenuAction = typeof options.onRowMenuAction === 'function' ? options.onRowMenuAction : null;\n this.onAction = typeof options.onAction === 'function' ? options.onAction : null;\n this.rowsDraggable = options.rowsDraggable === true;\n this._items = new Map(); // key \u2192 the item drawn for it\n this._onClick = (e) => this._click(e);\n this._onKey = (e) => this._key(e);\n this._onMenu = (e) => this._menu(e);\n }\n\n /** Pure and static-only \u2014 it runs inside `TileBase`'s constructor. */\n getDefaultConfig() {\n return { title: '', empty_text: '', max_rows: 0 };\n }\n\n getConfigSchema() {\n return {\n fields: [\n { key: 'title', type: 'text', label: 'Tile title' },\n { key: 'empty_text', type: 'text', label: 'When there is nothing',\n description: 'What the tile says when the list is empty, e.g. \"Nothing is late.\"' },\n { key: 'max_rows', type: 'number', label: 'Rows at most', min: 0,\n description: '0 shows them all; the tile scrolls.' },\n ],\n };\n }\n\n mount(container) {\n super.mount(container);\n applyTitle(this);\n const c = this.contentElement;\n if (!c) return;\n // On the content element, which outlives every render (they replace\n // its children, never it), so one set of listeners serves them all.\n c.addEventListener('click', this._onClick);\n c.addEventListener('keydown', this._onKey);\n c.addEventListener('contextmenu', this._onMenu);\n }\n\n /** `null` is \"the grid has no data\" \u2014 see `ChartTile.update`. */\n update(data, config) {\n if (this._disposed) return;\n super.update(data === null ? undefined : data, config);\n if (config) applyTitle(this);\n }\n\n /** Hand this tile its rows; null is the empty state. */\n setData(data) {\n if (this._disposed) return;\n this.data = data ?? null;\n if (this.contentElement) this.render(this.data);\n }\n\n /** The item drawn under `key`, or null. */\n itemFor(key) { return this._items.get(String(key)) ?? null; }\n\n /** The element of the item drawn under `key`, or null. */\n rowElement(key) {\n const want = String(key);\n return [...(this.contentElement?.querySelectorAll('[data-row-key]') || [])]\n .find((r) => r.dataset.rowKey === want) || null;\n }\n\n render(data) {\n const content = this.contentElement;\n if (!content) return;\n const norm = normalize(data, this.constructor._KEY);\n this._items.clear();\n if (!norm) { this.showEmpty('Nothing to show.'); return; }\n\n const max = Math.max(0, Math.floor(Number(this.config.max_rows) || 0));\n const shown = max ? norm.items.slice(0, max) : norm.items;\n const box = el('div', `fd-list-tile fd-list-tile--${this.constructor._KEY}`);\n\n const bar = el('div', 'fd-list-tile__bar');\n const count = el('span', 'fd-list-tile__count',\n shown.length < norm.total ? `${shown.length} of ${norm.total}` : String(norm.total));\n count.title = `${norm.total} in all`;\n bar.append(count, el('span', 'fd-list-tile__spacer'));\n if (norm.action) {\n const b = el('button', 'fd-list-tile__action');\n b.type = 'button';\n b.dataset.listAction = 'action';\n if (norm.action.icon) b.append(glyph(norm.action.icon));\n b.append(el('span', null, norm.action.label));\n bar.append(b);\n }\n box.append(bar);\n\n const list = el('div', 'fd-list-tile__rows');\n list.setAttribute('role', 'list');\n if (!shown.length) {\n list.append(el('div', 'fd-list-tile__empty', norm.empty || this.config.empty_text || 'Nothing here.'));\n }\n for (const item of shown) {\n const key = String(item.key);\n if (this._items.has(key)) continue; // one row per key: a second would be unreachable\n this._items.set(key, item);\n const row = this._renderItem(item);\n row.classList.add('fd-list-tile__row');\n row.dataset.rowKey = key;\n row.setAttribute('role', 'button');\n row.tabIndex = 0;\n if (this.rowsDraggable) row.draggable = true;\n const wrap = el('div', 'fd-list-tile__item');\n wrap.setAttribute('role', 'listitem');\n wrap.append(row);\n list.append(wrap);\n }\n box.append(list);\n if (norm.note) {\n const note = el('div', 'fd-list-tile__note', norm.note);\n note.setAttribute('role', 'note');\n note.title = norm.note;\n box.append(note);\n }\n content.replaceChildren(box);\n }\n\n /** One item's row element. @abstract */\n _renderItem(_item) { return el('div'); }\n\n // \u2500\u2500 input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _rowOf(target) {\n const row = target?.closest?.('[data-row-key]');\n return row && this.contentElement?.contains(row) ? row : null;\n }\n\n _click(e) {\n if (e.target?.closest?.('[data-list-action]')) {\n this._call(this.onAction, { tile: this, event: e });\n return;\n }\n const row = this._rowOf(e.target);\n if (row) this._activate(row, e);\n }\n\n _activate(rowEl, event) {\n const row = this.itemFor(rowEl.dataset.rowKey);\n if (row) this._call(this.onRowActivate, { row, event, tile: this });\n }\n\n _key(e) {\n const rowEl = this._rowOf(e.target);\n if (!rowEl) return;\n if (e.key === 'ContextMenu' || (e.key === 'F10' && e.shiftKey)) {\n const r = rowEl.getBoundingClientRect();\n if (this._openMenu(rowEl, e, r.left + 16, r.bottom)) e.preventDefault();\n return;\n }\n if ((e.key === 'Enter' || e.key === ' ') && !e.altKey) {\n e.preventDefault();\n this._activate(rowEl, e);\n return;\n }\n const rows = [...this.contentElement.querySelectorAll('[data-row-key]')];\n const i = rows.indexOf(rowEl);\n const to = { ArrowDown: i + 1, ArrowUp: i - 1, Home: 0, End: rows.length - 1 }[e.key];\n if (to === undefined || !rows[to]) return;\n e.preventDefault();\n rows[to].focus();\n }\n\n _menu(e) {\n const rowEl = this._rowOf(e.target);\n if (rowEl && this._openMenu(rowEl, e, e.clientX, e.clientY)) e.preventDefault();\n }\n\n /** Show the row's menu, if it has one. \u2192 whether it did. */\n _openMenu(rowEl, event, x, y) {\n const row = this.itemFor(rowEl.dataset.rowKey);\n if (!row || typeof this.rowMenu !== 'function') return false;\n let items = null;\n try { items = this.rowMenu({ row, event, tile: this }); }\n catch (err) { console.error(`[${this.constructor.name}] rowMenu threw:`, err); return false; }\n if (!Array.isArray(items) || !items.length) return false;\n showContextMenu(x, y, items, (action) => this._call(this.onRowMenuAction, { action, row, tile: this }));\n return true;\n }\n\n /** A hook, called so that one that throws is reported and the tile goes on. */\n _call(fn, arg) {\n if (typeof fn !== 'function') return;\n try { fn(arg); } catch (err) { console.error(`[${this.constructor.name}] a callback threw:`, err); }\n }\n\n dispose() {\n const c = this.contentElement;\n if (c) {\n c.removeEventListener('click', this._onClick);\n c.removeEventListener('keydown', this._onKey);\n c.removeEventListener('contextmenu', this._onMenu);\n }\n this._items.clear();\n super.dispose();\n }\n}\n\n/**\n * A LIST OF RECORDS: an icon, a lead (a reference, say), the title, and cells.\n * See the header for the data and the input.\n */\nexport class ListTile extends RowsTile {\n static TYPE = 'flexdesk.list';\n static TITLE = 'List';\n static ICON = 'list';\n static DESCRIPTION = 'Rows you supply, with a count, a click and a right-click menu per row.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 2, maxW: 12, maxH: 12 };\n static _KEY = 'rows';\n\n _renderItem(r) {\n const row = el('div', r.className ? String(r.className) : null);\n if (r.icon) {\n const g = glyph(r.icon, 'fd-list-tile__icon');\n if (r.iconTitle) { g.title = r.iconTitle; g.removeAttribute('aria-hidden'); }\n row.append(g);\n }\n if (r.lead != null && r.lead !== '') row.append(el('span', 'fd-list-tile__lead', r.lead));\n const title = el('span', 'fd-list-tile__title', r.title ?? '');\n title.title = r.tip || String(r.title ?? '');\n row.append(title);\n for (const c of Array.isArray(r.cells) ? r.cells : []) {\n if (!c) continue;\n const cell = el('span', `fd-list-tile__cell${toneClass('fd-list-tile__cell', c.tone)}${c.className ? ` ${c.className}` : ''}`);\n if (c.icon) cell.append(glyph(c.icon));\n if (c.text != null && c.text !== '') cell.append(document.createTextNode(String(c.text)));\n if (c.title) cell.title = c.title;\n row.append(cell);\n }\n return row;\n }\n}\n\n/**\n * WHO HAS WHAT: one row per person, with a count and pills. The order is the\n * embedder's (the list is read top-down and stopped at, so the order should BE\n * the priority); `groupByPerson` is a starting point for building it.\n */\nexport class PeopleTile extends RowsTile {\n static TYPE = 'flexdesk.people';\n static TITLE = 'People';\n static ICON = 'groups';\n static DESCRIPTION = 'One row per person, with how much is on them.';\n static DEFAULT_SIZE = { w: 6, h: 4 };\n static SIZE_CONSTRAINTS = { minW: 3, minH: 2, maxW: 12, maxH: 12 };\n static _KEY = 'people';\n\n getDefaultConfig() {\n return { ...super.getDefaultConfig(), count_label: 'open' };\n }\n\n getConfigSchema() {\n const { fields } = super.getConfigSchema();\n return { fields: [...fields, { key: 'count_label', type: 'text', label: 'Count reads',\n description: 'After each person\\'s number, e.g. \"open\" for \"3 open\".' }] };\n }\n\n _renderItem(p) {\n const row = el('div', 'fd-people-tile__row');\n row.append(glyph(p.icon || (p.muted ? 'person_off' : 'person'), 'fd-list-tile__icon'));\n row.append(el('span', `fd-people-tile__name${p.muted ? ' fd-people-tile__name--muted' : ''}`, p.name ?? p.key));\n const pills = el('span', 'fd-people-tile__pills');\n for (const pill of Array.isArray(p.pills) ? p.pills : []) {\n if (!pill?.text) continue;\n const s = el('span', `fd-people-tile__pill${toneClass('fd-people-tile__pill', pill.tone)}`, pill.text);\n if (pill.title) s.title = pill.title;\n pills.append(s);\n }\n row.append(pills);\n const label = p.countLabel ?? this.config.count_label ?? '';\n row.append(el('span', 'fd-people-tile__count', `${Number(p.count) || 0}${label ? ` ${label}` : ''}`));\n if (p.title) row.title = p.title;\n return row;\n }\n}\n\n/**\n * Items grouped by person: `[{key, items}]`, most items first, then by key, the\n * nobody group (key `''`) last among equals. `personOf(item)` answers the\n * person's key, or a falsy value for nobody.\n */\nexport function groupByPerson(items, personOf) {\n const by = new Map();\n for (const item of Array.isArray(items) ? items : []) {\n const who = String(personOf(item) || '');\n if (!by.has(who)) by.set(who, { key: who, items: [] });\n by.get(who).items.push(item);\n }\n return [...by.values()].sort((a, b) => b.items.length - a.items.length\n || (a.key === '') - (b.key === '') || a.key.localeCompare(b.key));\n}\n\n/**\n * Register both tiles. Idempotent, and nothing registers at import time \u2014 see\n * `registerChartTiles`.\n */\nexport function registerListTiles() {\n for (const Tile of [ListTile, PeopleTile]) {\n if (getWidget(Tile.TYPE) !== Tile) registerWidget(Tile);\n }\n}\n\n/** The header shows `config.title`, else the type's own title. */\nfunction applyTitle(tile) {\n tile.setTitle(tile.config.title || tile.constructor.TITLE);\n}\n", "/**\n * scope_picker.js \u2014 ONE FILTER FOR THE WHOLE BOARD (0.16.1).\n *\n * A row of buttons, one per scope (\"Everyone\", \"Assigned by me\", \u2026), exactly\n * one of them pressed. It is the control half of a dashboard-level filter; the\n * other half is `TileGrid.setScope()`, which hands the value to every tile\n * (`tile.scope`, `tile.onScopeChange`) and to the grid's `onScopeChange`:\n *\n * const picker = createScopePicker({\n * options: [{ value: 'all', label: 'Everyone' },\n * { value: 'mine', label: 'Mine', hint: 'only what is on me' }],\n * value: 'all',\n * onChange: (value) => grid.setScope(value),\n * });\n * header.append(picker.element);\n *\n * What a scope MEANS is the embedder's: the grid only carries the value, and a\n * tile that knows nothing about scopes is unaffected by one.\n *\n * Each button has `aria-pressed`, the group a label. Left and Right move the\n * focus along the row and Enter or Space presses, as on any button; a click on\n * the button already pressed changes nothing and calls nothing.\n */\n\n/**\n * @param {Object} o\n * @param {Array<{value: string, label: string, hint?: string}>} o.options\n * @param {string} [o.value] - The pressed one; the first option when absent or unknown.\n * @param {string} [o.label='Scope'] - The group's accessible name.\n * @param {(value: string) => void} [o.onChange] - After the user presses another one.\n * @returns {{element: HTMLElement, readonly value: string, setValue: (v: string) => void, dispose: () => void}}\n */\nexport function createScopePicker({ options = [], value, label = 'Scope', onChange } = {}) {\n const opts = options.filter((o) => o && o.value != null).map((o) => ({ ...o, value: String(o.value) }));\n const known = (v) => opts.some((o) => o.value === String(v));\n let current = known(value) ? String(value) : opts[0]?.value ?? '';\n\n const element = document.createElement('span');\n element.className = 'fd-scope-picker';\n element.setAttribute('role', 'group');\n element.setAttribute('aria-label', label);\n\n const buttons = opts.map((o) => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'fd-scope-picker__btn';\n b.dataset.scope = o.value;\n b.textContent = o.label ?? o.value;\n if (o.hint) b.title = o.hint;\n element.append(b);\n return b;\n });\n\n const paint = () => {\n for (const b of buttons) {\n const on = b.dataset.scope === current;\n b.classList.toggle('fd-scope-picker__btn--on', on);\n b.setAttribute('aria-pressed', String(on));\n }\n };\n paint();\n\n const onClick = (e) => {\n const b = e.target?.closest?.('[data-scope]');\n if (!b || !element.contains(b) || b.dataset.scope === current) return;\n current = b.dataset.scope;\n paint();\n try { onChange?.(current); } catch (err) { console.error('[ScopePicker] onChange threw:', err); }\n };\n const onKey = (e) => {\n const i = buttons.indexOf(e.target);\n if (i < 0) return;\n const to = { ArrowRight: i + 1, ArrowLeft: i - 1, Home: 0, End: buttons.length - 1 }[e.key];\n if (to === undefined || !buttons[to]) return;\n e.preventDefault();\n buttons[to].focus();\n };\n element.addEventListener('click', onClick);\n element.addEventListener('keydown', onKey);\n\n return {\n element,\n get value() { return current; },\n /** Press `v` without calling `onChange` (a value restored from elsewhere). */\n setValue(v) {\n if (!known(v)) return;\n current = String(v);\n paint();\n },\n dispose() {\n element.removeEventListener('click', onClick);\n element.removeEventListener('keydown', onKey);\n element.remove();\n },\n };\n}\n", "/**\n * tile_config_form.js \u2014 a tile's config schema drawn as a form (0.17.0).\n *\n * `TileBase.getConfigSchema()` answers `{fields: [...]}` and `config_schema.js`\n * knows how to validate, default and list options for those fields. This draws\n * them, so an embedder no longer hand-builds a control per field:\n *\n * import { mountTileConfigForm } from '@flexdesk/tiles';\n * const form = mountTileConfigForm(host, {\n * schema: tile.getConfigSchema(),\n * config: tile.config,\n * data, // for `options: 'variables'` and the like\n * onChange: (key, value, config) => tile.update(undefined, config),\n * renderers: { variable: (ctx) => myPicker(ctx) },\n * });\n * form.getValues(); form.setValues(next); form.isValid();\n * form.focusFirstInvalid(); form.flush(); form.dispose();\n *\n * \u2550\u2550 A FIELD \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 * { key, type, label?, description?, default?, required?, readonly?,\n * min?, max?, step?, options?, visibleWhen? }\n *\n * `type` is a `FieldTypes` entry (text, number, checkbox, select, multiselect,\n * color, range) or a type a consumer renders through `renderers`. `options` is\n * what `getFieldOptions(field, data)` reads. `visibleWhen` is\n * `{field, in: [...]}` or `{field, equals}`: the row is hidden while the other\n * field's value does not match, and shown again when it does \u2014 by toggling the\n * row, never by rebuilding the form, so the control being typed into keeps its\n * focus and its caret.\n *\n * A field with no `key` throws: a form that wrote every edit to\n * `config['undefined']` was BUG-0021, and a loud mount is the cheaper failure.\n * So does a `type` with neither a built-in control nor a renderer. `label` is\n * optional: without one the field is called by its `key`, on its label and in\n * every message (`count must be at least 1`).\n *\n * \u2550\u2550 AN EDIT \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 * Every edit is checked by `validateField`. A valid one is applied and calls\n * `onChange(key, value, config)` with a copy of the whole config. An invalid one\n * shows its error under the field and is NOT applied: the config keeps the last\n * valid value until the field is corrected (or `setValues` replaces it).\n * `setValues` does not call `onChange`. `isValid()` answers false while a\n * shown row has an error; `focusFirstInvalid()` focuses the first such row's\n * control (a renderer's element, or the first focusable element inside it) and\n * answers whether there was one.\n *\n * `commitOn: 'input'` (the default) checks text, number, range and colour\n * controls on every keystroke. `commitOn: 'change'` checks them when the edit is\n * finished (the control's `change`: blur, Enter, a released slider), for a\n * consumer whose `onChange` is expensive \u2014 a save, a reload. A range still shows\n * its value as it moves. `flush()` commits an edit typed but not yet finished,\n * for a consumer about to take the form away; it is a no-op under `'input'`.\n *\n * \u2550\u2550 A CONSUMER'S CONTROL \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 * `renderers[type](ctx)` \u2014 consulted before the built-ins, so it may also\n * replace one \u2014 gets `{field, key, value, data, readonly, commit}` and returns an\n * element, or `{element, setValue?(value), dispose?()}`. `commit(value)` runs\n * the same check as a built-in edit and answers `{valid, error?}`. On a\n * `readonly` field it applies nothing and answers `{valid: false, error}`, as a\n * built-in control on a readonly field is disabled and never commits.\n *\n * \u2550\u2550 THE GRID'S COGWHEEL \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 * `TileGrid` emits `grid:config-modal-show` and nothing listens by default.\n * `openTileConfig(eventBus, opts)` is the opt-in listener: it shows the form in\n * a `SlideOutPanel` over `opts.host` (every finished, valid edit is saved \u2014 the\n * form runs `commitOn: 'change'`, so a typed title is one save, not one per\n * keystroke; closing the panel saves an edit still being typed) or in a modal\n * (saved on Save, which is refused while a field shows an error: the modal\n * stays open and the first invalid field gets the focus). A request that arrives while a modal is open is\n * ignored: the open modal is the one being answered. It answers a function that\n * unsubscribes; it also closes the slide-out, but leaves an open modal alone \u2014\n * that modal stays working (its Save still saves) until the user dismisses it.\n */\n\nimport {\n FieldTypes, validateField, mergeWithDefaults, getFieldOptions,\n} from './config_schema.js';\nimport { SlideOutPanel } from '../ui/components/slide_out_panel.js';\nimport { openModal } from '../ui/components/modal.js';\n\nlet _seq = 0;\n// What focusFirstInvalid may focus inside a renderer's element.\nconst FOCUSABLE = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), '\n + 'button:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]';\n\nfunction el(tag, className, text) {\n const n = document.createElement(tag);\n if (className) n.className = className;\n if (text != null) n.textContent = String(text);\n return n;\n}\n\nfunction isVisible(field, values) {\n const rule = field.visibleWhen;\n if (!rule) return true;\n const v = values[rule.field];\n if (Array.isArray(rule.in)) return rule.in.includes(v);\n if ('equals' in rule) return v === rule.equals;\n return true;\n}\n\n/** Built-in controls: each answers `{element, read(), write(value)}`. */\nconst BUILT_IN = {\n [FieldTypes.TEXT]: (field, id) => {\n const input = el('input', 'fd-tile-config__input');\n input.type = 'text';\n input.id = id;\n return {\n element: input, events: ['input'],\n read: () => input.value,\n write: (v) => { input.value = v == null ? '' : String(v); },\n };\n },\n [FieldTypes.NUMBER]: (field, id) => numeric(field, id, 'number'),\n [FieldTypes.RANGE]: (field, id) => numeric(field, id, 'range'),\n [FieldTypes.CHECKBOX]: (field, id) => {\n const input = el('input', 'fd-tile-config__checkbox');\n input.type = 'checkbox';\n input.id = id;\n return {\n element: input, events: ['change'],\n read: () => input.checked,\n write: (v) => { input.checked = !!v; },\n };\n },\n [FieldTypes.COLOR]: (field, id) => {\n const input = el('input', 'fd-tile-config__color');\n input.type = 'color';\n input.id = id;\n return {\n element: input, events: ['input'],\n read: () => input.value,\n write: (v) => { if (v) input.value = String(v); },\n };\n },\n [FieldTypes.SELECT]: (field, id, data) => choice(field, id, data, false),\n [FieldTypes.MULTISELECT]: (field, id, data) => choice(field, id, data, true),\n};\n\nfunction numeric(field, id, kind) {\n const input = el('input', `fd-tile-config__${kind === 'range' ? 'range' : 'input'}`);\n input.type = kind;\n input.id = id;\n if (field.min != null) input.min = String(field.min);\n if (field.max != null) input.max = String(field.max);\n if (field.step != null) input.step = String(field.step);\n const out = kind === 'range' ? el('output', 'fd-tile-config__range-value') : null;\n const element = out ? el('span', 'fd-tile-config__range-wrap') : input;\n if (out) element.append(input, out);\n return {\n element, events: ['input'],\n // The raw text goes to `validateField`; the form turns it into a number.\n read: () => input.value,\n write: (v) => {\n input.value = v == null ? '' : String(v);\n if (out) out.textContent = input.value;\n },\n shown: (v) => { if (out) out.textContent = v == null ? '' : String(v); },\n };\n}\n\nfunction choice(field, id, data, multiple) {\n const select = el('select', 'fd-tile-config__select');\n select.id = id;\n select.multiple = multiple;\n // Option values keep their type (a number stays a number) \u2014 they are read\n // back from this array by index, never from the element's string value.\n const options = getFieldOptions(field, data);\n options.forEach((o) => select.append(el('option', null, o.label ?? o.value)));\n return {\n element: select, events: ['change'],\n read: () => (multiple\n ? options.filter((_, i) => select.options[i].selected).map((o) => o.value)\n : (options[select.selectedIndex]?.value ?? null)),\n write: (v) => {\n if (multiple) {\n const want = Array.isArray(v) ? v : [];\n options.forEach((o, i) => { select.options[i].selected = want.includes(o.value); });\n } else {\n select.selectedIndex = options.findIndex((o) => o.value === v);\n }\n },\n };\n}\n\n/** Number and range read as text; an empty one is null. */\nfunction coerce(field, raw) {\n if (field.type === FieldTypes.NUMBER || field.type === FieldTypes.RANGE) {\n return raw === '' || raw == null ? null : Number(raw);\n }\n return raw;\n}\n\n/**\n * Draw `schema.fields` into `host`.\n * @param {'input'|'change'} [opts.commitOn='input'] When a text, number, range\n * or colour control is checked and committed: on every keystroke, or once the\n * edit is finished.\n * @returns {{getValues(): Object, setValues(config: Object): void,\n * isValid(): boolean, focusFirstInvalid(): boolean, flush(): void,\n * dispose(): void}}\n */\nexport function mountTileConfigForm(host, {\n schema, config = {}, data = null, onChange = null, renderers = {}, commitOn = 'input',\n} = {}) {\n if (!host) throw new TypeError('mountTileConfigForm: a host element is required');\n if (commitOn !== 'input' && commitOn !== 'change') {\n throw new TypeError(`mountTileConfigForm: unknown commitOn \"${commitOn}\"`);\n }\n const fields = Array.isArray(schema?.fields) ? schema.fields : [];\n fields.forEach((f, i) => {\n if (typeof f?.key !== 'string' || !f.key) {\n const called = typeof f?.label === 'string' && f.label ? ` \"${f.label}\"` : '';\n throw new TypeError(`mountTileConfigForm: field #${i + 1}${called} has no key`);\n }\n });\n\n let values = mergeWithDefaults(config || {}, schema);\n const unlisten = []; // listeners removed by dispose\n const root = el('div', 'fd-tile-config');\n const rows = []; // {field, named, row, error, control, invalid, pending}\n\n const showError = (r, message) => {\n r.invalid = !!message;\n r.error.textContent = message || '';\n r.error.hidden = !message;\n r.row.classList.toggle('fd-tile-config__row--invalid', !!message);\n };\n\n const applyVisibility = () => {\n for (const r of rows) r.row.hidden = !isVisible(r.field, values);\n };\n\n const commit = (r, raw) => {\n if (r.field.readonly) return { valid: false, error: `${r.named.label} is read-only` };\n const result = validateField(raw, r.named);\n if (!result.valid) {\n showError(r, result.error);\n return { valid: false, error: result.error };\n }\n showError(r, null);\n const value = coerce(r.field, raw);\n values = { ...values, [r.field.key]: value };\n applyVisibility();\n onChange?.(r.field.key, value, { ...values });\n return { valid: true };\n };\n\n for (const field of fields) {\n const id = `fd-tile-config-${++_seq}`;\n const row = el('div', `fd-tile-config__row fd-tile-config__row--${field.type}`);\n row.setAttribute('data-field', field.key);\n // What validateField and the messages read: the label, or the key.\n const named = { ...field, label: field.label ?? field.key };\n const label = el('label', 'fd-tile-config__label', named.label);\n const error = el('div', 'fd-tile-config__error');\n error.hidden = true;\n const r = { field, named, row, error, control: null, invalid: false, pending: null };\n\n const custom = renderers?.[field.type];\n if (typeof custom === 'function') {\n const made = custom({\n field, key: field.key, value: values[field.key], data,\n readonly: !!field.readonly, commit: (v) => commit(r, v),\n });\n const element = made instanceof HTMLElement ? made : made?.element;\n if (!(element instanceof HTMLElement)) {\n throw new TypeError(`mountTileConfigForm: the renderer for \"${field.type}\" returned no element`);\n }\n element.id ||= id;\n // The id the control carries: a renderer may have set its own.\n label.htmlFor = element.id;\n r.control = {\n element,\n write: made instanceof HTMLElement ? () => {} : (v) => made.setValue?.(v),\n dispose: made instanceof HTMLElement ? null : () => made.dispose?.(),\n };\n } else {\n const build = BUILT_IN[field.type];\n if (!build) {\n throw new TypeError(`mountTileConfigForm: no control for type \"${field.type}\" (field \"${field.key}\"); pass a renderer`);\n }\n const c = build(field, id, data);\n label.htmlFor = id;\n c.write(values[field.key]);\n const input = c.element.matches('input, select') ? c.element : c.element.querySelector('input, select');\n if (field.readonly) {\n input.disabled = true;\n } else {\n const listen = (type, fn) => {\n input.addEventListener(type, fn);\n unlisten.push(() => input.removeEventListener(type, fn));\n };\n const onEdit = () => {\n r.pending = null;\n const raw = c.read();\n c.shown?.(raw);\n commit(r, raw);\n };\n if (commitOn === 'change') {\n // Checked once the edit is finished; until then it is\n // pending, so flush() can still commit it.\n listen('change', onEdit);\n if (c.events.includes('input')) {\n listen('input', () => { r.pending = onEdit; c.shown?.(c.read()); });\n }\n } else {\n for (const type of c.events) listen(type, onEdit);\n }\n }\n r.control = c;\n }\n\n if (field.type === FieldTypes.CHECKBOX) row.append(r.control.element, label);\n else row.append(label, r.control.element);\n if (field.description) row.append(el('div', 'fd-tile-config__help', field.description));\n row.append(error);\n rows.push(r);\n root.append(row);\n }\n\n applyVisibility();\n host.append(root);\n\n return {\n getValues: () => ({ ...values }),\n setValues(next) {\n values = mergeWithDefaults(next || {}, schema);\n for (const r of rows) {\n r.pending = null;\n r.control.write(values[r.field.key]);\n showError(r, null);\n }\n applyVisibility();\n },\n isValid: () => rows.every((r) => r.row.hidden || !r.invalid),\n focusFirstInvalid() {\n const r = rows.find((x) => !x.row.hidden && x.invalid);\n if (!r) return false;\n const { element } = r.control;\n const target = element.matches(FOCUSABLE) ? element : element.querySelector(FOCUSABLE);\n (target || element).focus();\n return true;\n },\n flush() {\n for (const r of rows) r.pending?.();\n },\n dispose() {\n unlisten.splice(0).forEach((off) => off());\n for (const r of rows) {\n try { r.control.dispose?.(); } catch (err) { console.warn('[tile-config] a renderer dispose threw', err); }\n }\n rows.length = 0;\n root.remove();\n },\n };\n}\n\n/**\n * Show `grid:config-modal-show` requests as a config form.\n *\n * @param {{on(name: string, handler: Function): {dispose(): void}}} eventBus\n * The `EventBus` the `TileGrid` emits on.\n * @param {object} [opts]\n * @param {'modal'|'slide-out'} [opts.mode='modal'] A modal saves on Save, and\n * refuses Save while a field shows an error; a slide-out saves every\n * finished, valid edit (`commitOn: 'change'`).\n * @param {HTMLElement} [opts.host] The slide-out's host (required for it).\n * @param {number} [opts.width] The slide-out's or the modal's width.\n * @param {Object} [opts.renderers] Passed to `mountTileConfigForm`.\n * @param {string|Function} [opts.title='Tile settings'] Or `(detail) => string`.\n * @returns {() => void} Unsubscribes and closes the slide-out. An open modal is\n * left to the user: it keeps its form, and its Save still calls `onSave`.\n */\nexport function openTileConfig(eventBus, { mode = 'modal', host = null, width, renderers = {}, title = 'Tile settings' } = {}) {\n if (typeof eventBus?.on !== 'function') throw new TypeError('openTileConfig: an event bus with on() is required');\n if (mode !== 'modal' && mode !== 'slide-out') throw new TypeError(`openTileConfig: unknown mode \"${mode}\"`);\n if (mode === 'slide-out' && !(host instanceof HTMLElement)) {\n throw new TypeError('openTileConfig: a slide-out needs a host element');\n }\n\n let form = null; // the slide-out's form\n let panel = null;\n let modalOpen = false;\n // An edit still being typed when the panel goes is saved, not lost.\n const drop = () => { form?.flush(); form?.dispose(); form = null; };\n\n const show = (detail = {}) => {\n if (modalOpen) return;\n const heading = typeof title === 'function' ? title(detail) : title;\n const base = { schema: detail.schema, config: detail.config, data: detail.data ?? null, renderers };\n\n if (mode === 'slide-out') {\n drop();\n if (!panel) {\n panel = new SlideOutPanel({ ...(width ? { width } : {}), onClose: drop });\n panel.mount(host);\n }\n const body = panel.open(heading, 'tune');\n form = mountTileConfigForm(body, {\n ...base, commitOn: 'change', onChange: (_k, _v, cfg) => detail.onSave?.(cfg),\n });\n return;\n }\n\n // The modal's form lives until the user dismisses the modal, whatever\n // else happens meanwhile: requests are ignored while it is open, and\n // the returned function leaves it alone.\n const content = el('div', 'fd-tile-config-host');\n const mine = mountTileConfigForm(content, base);\n modalOpen = true;\n openModal({\n title: heading, icon: 'tune', content, ...(width ? { width } : {}),\n actions: [\n { label: 'Cancel', value: null },\n // Refused while a field shows an error: its last valid value is\n // not what the user is looking at, so saving it would be a lie.\n { label: 'Save', value: 'save', primary: true, keepOpen: true, onClick: (close) => {\n if (mine.isValid()) { close('save'); return; }\n mine.focusFirstInvalid();\n } },\n ],\n }).then((v) => {\n modalOpen = false;\n if (v === 'save') detail.onSave?.(mine.getValues());\n mine.dispose();\n });\n };\n\n const sub = eventBus.on('grid:config-modal-show', show);\n\n return () => {\n sub.dispose();\n drop();\n panel?.dispose();\n panel = null;\n };\n}\n", "/**\n * tile_grid.js\n *\n * Core draggable tile grid system.\n * Manages a 12-column CSS grid with drag-and-drop repositioning and resize functionality.\n */\n\nimport { createWidget, getWidgetCatalog } from './tile_registry.js';\nimport { ActionDropdown } from '../ui/components/action_dropdown.js';\n\nexport class TileGrid {\n /**\n * @param {Object} options\n * @param {HTMLElement} options.container - Container element for the grid\n * @param {number} [options.columns=12] - Number of grid columns\n * @param {number} [options.rowHeight=80] - Height of each grid row in pixels\n * @param {number} [options.gap=16] - Gap between tiles in pixels\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {boolean} [options.showToolbar=true] - Whether to show built-in toolbar\n * @param {Function} [options.onLayoutChange] - Callback when layout changes\n * @param {Function} [options.onAddWidget] - Callback for add widget action\n * @param {Function} [options.onResetLayout] - Callback for reset layout action\n * @param {Function} [options.onExport] - Callback for export action\n * @param {{resolve: Function}} [options.dataSource] - Per-tile data provider,\n * handed to every tile. With none, the grid is the broadcast-only grid\n * it has always been and no tile is ever asked to load anything.\n * @param {*} [options.scope=null] - The board's scope, a filter every tile\n * follows (0.16.1); see `setScope`.\n * @param {Function} [options.onScopeChange] - `(scope)` after `setScope` changed it.\n */\n constructor({ container, columns = 12, rowHeight = 80, gap = 16, eventBus = null,\n showToolbar = true, readonly = false, onLayoutChange, onBeforeLayoutChange,\n onAddWidget, onResetLayout, onExport,\n // Handed down to every tile. TileBase used to import appHost() from\n // ui/js/ecoagent/ to back Expand -> Export CSV/PNG; a grid that has\n // no host simply gets the Blob-download fallback the host contract\n // promises. It is not an error to have none.\n host = null, stateGuard = null,\n // Injected, never constructed here: the grid does not know what\n // a binding is, only that a tile may have somewhere to ask.\n dataSource = null, scope = null, onScopeChange = null }) {\n this.host = host;\n this.scope = scope;\n this._onScopeChangeCallback = onScopeChange;\n this.stateGuard = stateGuard;\n this.dataSource = dataSource;\n this.container = container;\n this.columns = columns;\n this.rowHeight = rowHeight;\n this.gap = gap;\n this.eventBus = eventBus;\n this.showToolbar = showToolbar;\n this.readonly = readonly;\n this._onLayoutChangeCallback = onLayoutChange;\n this._onBeforeLayoutChangeCallback = onBeforeLayoutChange;\n this._onAddWidgetCallback = onAddWidget;\n this._onResetLayoutCallback = onResetLayout;\n this._onExportCallback = onExport;\n\n /** @type {Map<string, import('./tile_base.js').TileBase>} */\n this.tiles = new Map();\n\n /** @type {Array<{id: string, x: number, y: number, w: number, h: number}>} */\n this.layout = [];\n\n /** @type {Set<string>|null} IDs of documentation cells (for \"Show in Documentation\" visibility) */\n this.documentationCellIds = null;\n\n this.gridElement = null;\n this.data = null;\n this.fullData = null;\n\n // Drag state\n this._dragState = null;\n this._resizeState = null;\n this._ghostElement = null;\n\n // Bound handlers for cleanup\n this._boundOnPointerMove = this._onPointerMove.bind(this);\n this._boundOnPointerUp = this._onPointerUp.bind(this);\n\n this._init();\n }\n\n /**\n * Initialize the grid container.\n * @private\n */\n _init() {\n // Create grid element\n this.gridElement = document.createElement('div');\n this.gridElement.className = 'tile-grid';\n this.gridElement.style.setProperty('--grid-columns', this.columns);\n this.gridElement.style.setProperty('--grid-row-height', `${this.rowHeight}px`);\n this.gridElement.style.setProperty('--grid-gap', `${this.gap}px`);\n\n // Add grid to container\n this.container.innerHTML = '';\n this.container.appendChild(this.gridElement);\n\n // Add toolbar (can be disabled for external toolbar)\n if (this.showToolbar) {\n this._buildToolbar();\n }\n\n // Listen for tile events\n this.gridElement.addEventListener('tile:config-request', this._onTileConfigRequest.bind(this));\n this.gridElement.addEventListener('tile:remove-request', this._onTileRemoveRequest.bind(this));\n\n // Global pointer events for drag/resize\n document.addEventListener('pointermove', this._boundOnPointerMove);\n document.addEventListener('pointerup', this._boundOnPointerUp);\n }\n\n /**\n * Build the dashboard bottom toolbar with add widget dropdown.\n * @private\n */\n _buildToolbar() {\n const toolbar = document.createElement('div');\n toolbar.className = 'tile-grid-toolbar tile-grid-toolbar--bottom';\n this._toolbarElement = toolbar;\n\n toolbar.innerHTML = `\n <div class=\"toolbar-group toolbar-group--main\">\n <div class=\"add-widget-container\">\n <button class=\"toolbar-btn add-widget-btn twm-has-tooltip\" data-tooltip=\"Add widget\">\n <span class=\"material-symbols-outlined\">add</span>\n <span>Add Widget</span>\n <span class=\"material-symbols-outlined dropdown-arrow\">expand_less</span>\n </button>\n </div>\n <button class=\"toolbar-btn reset-layout-btn twm-has-tooltip\" data-tooltip=\"Reset to default layout\">\n <span class=\"material-symbols-outlined\">restart_alt</span>\n <span class=\"btn-text\">Reset</span>\n </button>\n <button class=\"toolbar-btn export-btn twm-has-tooltip\" data-tooltip=\"Export report\">\n <span class=\"material-symbols-outlined\">download</span>\n <span class=\"btn-text\">Export</span>\n </button>\n </div>\n `;\n\n // Create add-widget dropdown via ActionDropdown\n const addBtn = toolbar.querySelector('.add-widget-btn');\n const catalog = getWidgetCatalog();\n this._addWidgetDropdown = new ActionDropdown({\n trigger: addBtn,\n options: catalog.map(w => ({ type: w.type, label: w.title, icon: w.icon, description: w.description })),\n onSelect: (opt) => this._addWidgetFromDropdown(opt.type),\n className: 'add-widget-dropdown-menu'\n });\n\n toolbar.querySelector('.reset-layout-btn')?.addEventListener('click', () => this._resetLayout());\n toolbar.querySelector('.export-btn')?.addEventListener('click', () => this._exportReport());\n\n // Insert after grid element (at bottom)\n this.container.appendChild(toolbar);\n }\n\n /**\n * Add a widget from the dropdown selection.\n * @param {string} type - Widget type\n * @private\n */\n _addWidgetFromDropdown(type) {\n import('./tile_registry.js').then(({ getWidget }) => {\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n });\n }\n\n /**\n * Add a tile to the grid.\n * @param {string} type - Widget type\n * @param {Object} position - Grid position {x, y, w, h}\n * @param {Object} [config] - Widget configuration\n * @param {string} [id] - Optional tile ID (generated if not provided)\n * @returns {import('./tile_base.js').TileBase | null} The created tile or null\n */\n addTile(type, position, config = {}, id = null) {\n const tileId = id || `tile-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n\n const tile = createWidget(type, {\n id: tileId,\n grid: this,\n eventBus: this.eventBus,\n config,\n readonly: this.readonly,\n host: this.host,\n stateGuard: this.stateGuard,\n dataSource: this.dataSource,\n });\n\n if (!tile) return null;\n // Before mount, so a tile's first render and first load already follow it.\n tile.scope = this.scope;\n\n // Add to layout\n const layoutEntry = {\n id: tileId,\n type,\n x: position.x,\n y: position.y,\n w: position.w,\n h: position.h,\n config\n };\n this.layout.push(layoutEntry);\n\n // Store tile instance\n this.tiles.set(tileId, tile);\n\n // Mount to grid\n tile.mount(this.gridElement);\n this._applyTilePosition(tile, layoutEntry);\n\n // Setup drag handles\n this._setupTileDragHandlers(tile);\n\n // Render with current data if available\n if (this.data) {\n tile.fullData = this.fullData;\n tile.update(this.data);\n } else if (this.dataSource) {\n // A tile that fetches its own rows is never handed any, so the branch\n // above cannot fire for it and it would mount empty and stay empty\n // until something else happened to it. NOT awaited: `setLayout` calls\n // `addTile` in a loop, and awaiting here would serialise a board into\n // one request per tile in sequence \u2014 the opposite of what a batching\n // data source exists to do.\n tile.loadData?.();\n }\n\n // Emit layout changed\n this._emitLayoutChanged();\n\n return tile;\n }\n\n /**\n * Remove a tile from the grid.\n * @param {string} tileId - Tile ID to remove\n */\n removeTile(tileId) {\n const tile = this.tiles.get(tileId);\n if (!tile) return;\n\n tile.dispose();\n this.tiles.delete(tileId);\n\n // Remove from layout\n this.layout = this.layout.filter(l => l.id !== tileId);\n\n this._emitLayoutChanged();\n }\n\n /**\n * Update all tiles with new data.\n * @param {Object} data - Analytics data\n */\n setData(data) {\n this.data = data;\n this.tiles.forEach(tile => {\n tile.fullData = this.fullData;\n tile.update(data);\n });\n }\n\n /**\n * Ask every self-fetching tile to load again, bypassing whatever the data\n * source has cached.\n *\n * The counterpart of `setData` for the pull model: `setData` is how a caller\n * with one dataset for the whole board pushes it, and this is how a caller\n * whose tiles each own a query says \"that underlying data changed\". Passing\n * `ids` narrows it to the tiles a change actually touched, which is what an\n * invalidation carrying a table id can work out and a broadcast cannot.\n *\n * Not awaited and returns nothing: the tiles render themselves as their own\n * requests land, and a caller that waited for all of them would be waiting on\n * the slowest tile to show the fastest one.\n *\n * @param {string[]|Set<string>|null} [ids] - Tile ids, or null for all.\n */\n reloadAll(ids = null) {\n if (!this.dataSource) return;\n const wanted = ids ? new Set(ids) : null;\n this.tiles.forEach((tile, tileId) => {\n if (wanted && !wanted.has(tileId)) return;\n tile.loadData?.({ force: true });\n });\n }\n\n /**\n * THE BOARD'S SCOPE: one filter every tile follows (\"Everyone\", \"Assigned\n * by me\", \u2026), set from a `createScopePicker` or from anything else.\n *\n * The grid only carries the value; what it means is the embedder's. Every\n * tile gets it as `tile.scope` and through `tile.onScopeChange(scope)`, the\n * grid's `onScopeChange(scope)` is called, and a grid with a data source\n * reloads its tiles, since their rows depend on it. The scope is not part\n * of the layout: it is how the board is being looked at, not what is on it.\n *\n * @param {*} scope - Compared by JSON: setting the same scope again does nothing.\n * @returns {boolean} whether it changed\n */\n setScope(scope) {\n if (JSON.stringify(scope ?? null) === JSON.stringify(this.scope ?? null)) return false;\n this.scope = scope ?? null;\n this.tiles.forEach((tile) => {\n tile.scope = this.scope;\n try { tile.onScopeChange?.(this.scope); }\n catch (err) { console.error('[TileGrid] a tile\\'s onScopeChange threw:', err); }\n });\n try { this._onScopeChangeCallback?.(this.scope); }\n catch (err) { console.error('[TileGrid] onScopeChange threw:', err); }\n this.eventBus?.emit?.('grid:scope-changed', { scope: this.scope });\n if (this.dataSource) this.reloadAll();\n return true;\n }\n\n /**\n * Get current layout.\n * @returns {Array} Layout array\n */\n getLayout() {\n return this.layout.map(l => ({\n id: l.id,\n type: l.type,\n x: l.x,\n y: l.y,\n w: l.w,\n h: l.h,\n config: this.tiles.get(l.id)?.config || l.config\n }));\n }\n\n /**\n * Set layout and rebuild tiles.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n setLayout(layout) {\n // Clear existing tiles\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n // Clear grid content (keep toolbar)\n this.gridElement.innerHTML = '';\n\n // Handle both array and object with tiles property\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n // Rebuild from layout\n tilesArray.forEach(item => {\n this.addTile(item.type, {\n x: item.x,\n y: item.y,\n w: item.w,\n h: item.h\n }, item.config, item.id);\n });\n }\n\n /**\n * Apply CSS grid position to a tile element.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {{x: number, y: number, w: number, h: number}} position\n * @private\n */\n _applyTilePosition(tile, position) {\n if (!tile.element) return;\n\n tile.element.style.gridColumn = `${position.x + 1} / span ${position.w}`;\n tile.element.style.gridRow = `${position.y + 1} / span ${position.h}`;\n }\n\n /**\n * Setup drag and resize handlers for a tile.\n * @param {import('./tile_base.js').TileBase} tile\n * @private\n */\n _setupTileDragHandlers(tile) {\n if (!tile.element || this.readonly) return;\n\n const dragHandle = tile.element.querySelector('.tile-drag-handle');\n const resizeHandle = tile.element.querySelector('.tile-resize-handle');\n\n // Drag handle\n if (dragHandle) {\n dragHandle.addEventListener('pointerdown', (e) => this._onDragStart(tile, e));\n }\n\n // Resize handle\n if (resizeHandle) {\n resizeHandle.addEventListener('pointerdown', (e) => this._onResizeStart(tile, e));\n }\n }\n\n /**\n * Handle drag start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onDragStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = tile.element.getBoundingClientRect();\n const gridRect = this.gridElement.getBoundingClientRect();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._dragState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startGridX: layoutItem.x,\n startGridY: layoutItem.y,\n tileRect: rect,\n gridRect,\n w: layoutItem.w,\n h: layoutItem.h\n };\n\n tile.element.classList.add('dragging');\n\n // Create ghost element\n this._createGhost(rect);\n }\n\n /**\n * Handle resize start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onResizeStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n const gridRect = this.gridElement.getBoundingClientRect();\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._resizeState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startW: layoutItem.w,\n startH: layoutItem.h,\n gridRect,\n cellWidth,\n x: layoutItem.x,\n y: layoutItem.y\n };\n\n tile.element.classList.add('resizing');\n }\n\n /**\n * Handle pointer move (drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerMove(e) {\n if (this._dragState) {\n this._onDragMove(e);\n } else if (this._resizeState) {\n this._onResizeMove(e);\n }\n }\n\n /**\n * Handle drag move.\n * @param {PointerEvent} e\n * @private\n */\n _onDragMove(e) {\n const state = this._dragState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate cell dimensions\n const gridRect = state.gridRect;\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n const cellHeight = this.rowHeight;\n\n // Calculate new grid position\n const deltaGridX = Math.round(dx / (cellWidth + this.gap));\n const deltaGridY = Math.round(dy / (cellHeight + this.gap));\n\n let newX = state.startGridX + deltaGridX;\n let newY = state.startGridY + deltaGridY;\n\n // Clamp to grid bounds\n newX = Math.max(0, Math.min(newX, this.columns - state.w));\n newY = Math.max(0, newY);\n\n // Update ghost position\n if (this._ghostElement) {\n const ghostLeft = newX * (cellWidth + this.gap);\n const ghostTop = newY * (cellHeight + this.gap);\n this._ghostElement.style.transform = `translate(${ghostLeft}px, ${ghostTop}px)`;\n this._ghostElement.style.width = `${state.w * cellWidth + (state.w - 1) * this.gap}px`;\n this._ghostElement.style.height = `${state.h * cellHeight + (state.h - 1) * this.gap}px`;\n }\n\n // Store pending position\n state.pendingX = newX;\n state.pendingY = newY;\n }\n\n /**\n * Handle resize move.\n * @param {PointerEvent} e\n * @private\n */\n _onResizeMove(e) {\n const state = this._resizeState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate new size in grid cells\n const deltaW = Math.round(dx / (state.cellWidth + this.gap));\n const deltaH = Math.round(dy / (this.rowHeight + this.gap));\n\n let newW = state.startW + deltaW;\n let newH = state.startH + deltaH;\n\n // Get constraints\n const tileClass = state.tile.constructor;\n const constraints = tileClass.SIZE_CONSTRAINTS || { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n // Apply constraints\n newW = Math.max(constraints.minW, Math.min(newW, constraints.maxW));\n newH = Math.max(constraints.minH, Math.min(newH, constraints.maxH));\n\n // Don't exceed grid width\n newW = Math.min(newW, this.columns - state.x);\n\n // Live update tile size\n state.tile.element.style.gridColumn = `${state.x + 1} / span ${newW}`;\n state.tile.element.style.gridRow = `${state.y + 1} / span ${newH}`;\n\n state.pendingW = newW;\n state.pendingH = newH;\n }\n\n /**\n * Handle pointer up (end drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerUp(e) {\n if (this._dragState) {\n this._onDragEnd();\n } else if (this._resizeState) {\n this._onResizeEnd();\n }\n }\n\n /**\n * Handle drag end.\n * @private\n */\n _onDragEnd() {\n const state = this._dragState;\n if (!state) return;\n\n state.tile.element.classList.remove('dragging');\n this._removeGhost();\n\n // Update layout if position changed\n if (state.pendingX !== undefined && state.pendingY !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.x = state.pendingX;\n layoutItem.y = state.pendingY;\n this._applyTilePosition(state.tile, layoutItem);\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n }\n }\n\n this._dragState = null;\n }\n\n /**\n * Handle resize end.\n * @private\n */\n _onResizeEnd() {\n const state = this._resizeState;\n if (!state) return;\n\n state.tile.element.classList.remove('resizing');\n\n // Update layout if size changed\n if (state.pendingW !== undefined && state.pendingH !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.w = state.pendingW;\n layoutItem.h = state.pendingH;\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n\n // Re-render tile content for new size\n if (this.data) {\n state.tile.fullData = this.fullData;\n state.tile.update(this.data);\n } else {\n // Re-rendering from a dataset already in hand is free; asking\n // the server again because a tile got 40 px wider is not. A\n // self-fetching tile \u2014 or one the embedder feeds through\n // `setData` \u2014 is told the geometry settled and decides what\n // that costs it \u2014 for a chart, one `Plotly.Plots.resize`.\n state.tile.onResize?.();\n }\n }\n }\n\n this._resizeState = null;\n }\n\n /**\n * Check if two layout items overlap.\n * @param {Object} a - First layout item {x, y, w, h}\n * @param {Object} b - Second layout item {x, y, w, h}\n * @returns {boolean}\n * @private\n */\n _tilesOverlap(a, b) {\n return !(\n a.x + a.w <= b.x ||\n b.x + b.w <= a.x ||\n a.y + a.h <= b.y ||\n b.y + b.h <= a.y\n );\n }\n\n /**\n * Resolve overlaps by pushing tiles down.\n * @param {string} sourceTileId - The tile that was resized/moved\n * @private\n */\n _resolveOverlaps(sourceTileId) {\n const sourceItem = this.layout.find(l => l.id === sourceTileId);\n if (!sourceItem) return;\n\n // Sort tiles by y position (top to bottom), then by x\n const otherTiles = this.layout\n .filter(l => l.id !== sourceTileId)\n .sort((a, b) => a.y - b.y || a.x - b.x);\n\n let hasChanges = true;\n let iterations = 0;\n const maxIterations = 100; // Prevent infinite loops\n\n while (hasChanges && iterations < maxIterations) {\n hasChanges = false;\n iterations++;\n\n for (const item of otherTiles) {\n if (this._tilesOverlap(sourceItem, item)) {\n // Push this tile down to be below the source tile\n const newY = sourceItem.y + sourceItem.h;\n if (item.y !== newY) {\n item.y = newY;\n hasChanges = true;\n\n // Apply the new position visually\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n // Check for cascading overlaps among the moved tiles\n for (let i = 0; i < otherTiles.length; i++) {\n for (let j = i + 1; j < otherTiles.length; j++) {\n if (this._tilesOverlap(otherTiles[i], otherTiles[j])) {\n // Push the lower-index tile (earlier in sort order) doesn't need to move\n // Push the higher one down\n const pusher = otherTiles[i];\n const pushed = otherTiles[j];\n const newY = pusher.y + pusher.h;\n if (pushed.y < newY && this._tilesOverlap(pusher, pushed)) {\n pushed.y = newY;\n hasChanges = true;\n\n const tile = this.tiles.get(pushed.id);\n if (tile) {\n this._applyTilePosition(tile, pushed);\n }\n }\n }\n }\n }\n }\n\n // Compact the layout - remove vertical gaps\n this._compactLayout();\n }\n\n /**\n * Compact the layout by removing vertical gaps.\n * @private\n */\n _compactLayout() {\n // Sort tiles by y position\n const sortedTiles = [...this.layout].sort((a, b) => a.y - b.y || a.x - b.x);\n\n for (const item of sortedTiles) {\n // Try to move up as far as possible\n let newY = 0;\n\n while (newY < item.y) {\n const testPosition = { ...item, y: newY };\n\n // Check for overlaps with tiles above this one\n let hasOverlap = false;\n for (const other of this.layout) {\n if (other.id === item.id) continue;\n if (this._tilesOverlap(testPosition, other)) {\n hasOverlap = true;\n // Move below this overlapping tile\n newY = other.y + other.h;\n break;\n }\n }\n\n if (!hasOverlap) {\n break;\n }\n }\n\n if (newY < item.y) {\n item.y = newY;\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n /**\n * Create ghost element for drag preview.\n * @param {DOMRect} rect - Original tile rect\n * @private\n */\n _createGhost(rect) {\n this._ghostElement = document.createElement('div');\n this._ghostElement.className = 'tile-ghost';\n this.gridElement.appendChild(this._ghostElement);\n }\n\n /**\n * Remove ghost element.\n * @private\n */\n _removeGhost() {\n if (this._ghostElement) {\n this._ghostElement.remove();\n this._ghostElement = null;\n }\n }\n\n /**\n * Find next available position for a new tile.\n * @param {number} w - Width in cells\n * @param {number} h - Height in cells\n * @returns {{x: number, y: number}}\n */\n findNextPosition(w, h) {\n // Build occupancy grid\n const maxY = Math.max(...this.layout.map(l => l.y + l.h), 0);\n const occupied = new Set();\n\n this.layout.forEach(l => {\n for (let x = l.x; x < l.x + l.w; x++) {\n for (let y = l.y; y < l.y + l.h; y++) {\n occupied.add(`${x},${y}`);\n }\n }\n });\n\n // Find first available position\n for (let y = 0; y <= maxY + 1; y++) {\n for (let x = 0; x <= this.columns - w; x++) {\n let fits = true;\n for (let dx = 0; dx < w && fits; dx++) {\n for (let dy = 0; dy < h && fits; dy++) {\n if (occupied.has(`${x + dx},${y + dy}`)) {\n fits = false;\n }\n }\n }\n if (fits) {\n return { x, y };\n }\n }\n }\n\n // Default: place at bottom\n return { x: 0, y: maxY + 1 };\n }\n\n /**\n * Handle tile config request.\n * @param {CustomEvent} e\n * @private\n */\n _onTileConfigRequest(e) {\n const { tileId, tileType, config, schema } = e.detail;\n this.eventBus?.emit?.('grid:config-modal-show', {\n tileId,\n tileType,\n config,\n schema,\n // What `getFieldOptions` reads for a field with dynamic options.\n data: this.data,\n variables: this.data ? this._getVariableList() : [],\n onSave: (newConfig) => {\n const tile = this.tiles.get(tileId);\n if (tile) {\n tile.fullData = this.fullData;\n tile.update(this.data, newConfig);\n // A saved config is usually a changed BINDING, and the data\n // source's cache is keyed by the old one \u2014 so this is the one\n // reload that must not be served from it.\n if (this.dataSource) tile.loadData?.({ force: true });\n // Update layout config\n const layoutItem = this.layout.find(l => l.id === tileId);\n if (layoutItem) {\n layoutItem.config = newConfig;\n }\n this._emitLayoutChanged();\n }\n }\n });\n }\n\n /**\n * Handle tile remove request.\n * Note: Let the event bubble up to the dashboard which handles confirmation.\n * @param {CustomEvent} e\n * @private\n */\n _onTileRemoveRequest(e) {\n // Don't auto-remove - let event bubble up to dashboard\n // Dashboard shows a confirm dialog before calling removeTile()\n // Do NOT stop propagation - dashboard listener needs to receive this event\n }\n\n /**\n * Get list of available variables from data.\n * @returns {Array<{value: string, label: string}>}\n * @private\n */\n _getVariableList() {\n if (!this.data) return [];\n\n const variables = [];\n if (this.data.stocks) {\n Object.keys(this.data.stocks).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n if (this.data.indicators) {\n Object.keys(this.data.indicators).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n return variables;\n }\n\n /**\n * Show add widget menu.\n * @private\n */\n _showAddWidgetMenu() {\n this.eventBus?.emit?.('grid:add-widget-menu-show', {\n onSelect: (type) => {\n const { getWidget } = require('./tile_registry.js');\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n }\n });\n }\n\n /**\n * Reset to default layout.\n * @private\n */\n _resetLayout() {\n this.eventBus?.emit?.('grid:reset-layout-confirm', {\n onConfirm: () => {\n this.eventBus?.emit?.('grid:layout-reset-requested');\n }\n });\n }\n\n /**\n * Export report.\n * @private\n */\n _exportReport() {\n this.eventBus?.emit?.('grid:export-requested', {\n gridElement: this.gridElement,\n layout: this.getLayout()\n });\n }\n\n /**\n * Notify that a layout mutation is about to begin (drag/resize start).\n * @private\n */\n _emitBeforeLayoutChange() {\n if (typeof this._onBeforeLayoutChangeCallback === 'function') {\n this._onBeforeLayoutChangeCallback(this.getLayout());\n }\n }\n\n /**\n * Emit layout changed event and call the onLayoutChange callback.\n * @private\n */\n _emitLayoutChanged() {\n const layout = this.getLayout();\n this.eventBus?.emit?.('grid:layout-changed', { layout });\n\n // Call the callback if provided (used by ResultsTileDashboard for autosave)\n if (typeof this._onLayoutChangeCallback === 'function') {\n this._onLayoutChangeCallback(layout);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose() {\n document.removeEventListener('pointermove', this._boundOnPointerMove);\n document.removeEventListener('pointerup', this._boundOnPointerUp);\n\n this._addWidgetDropdown?.destroy();\n this._addWidgetDropdown = null;\n\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n if (this.gridElement) {\n this.gridElement.remove();\n this.gridElement = null;\n }\n }\n}\n\nexport default TileGrid;\n", "/**\n * @flexdesk/tiles \u2014 A draggable, resizable widget grid: the tile base class, the grid, the\n * widget registry, layout persistence, a chart and a KPI tile (0.13.0), a list and a\n * people tile and a board-wide scope picker (0.16.1), the figure tile every\n * Plotly tile draws through and the config form (0.17.0).\n *\n * It stores layouts under keys YOU choose and resolves starting templates\n * through a callback YOU supply. It has no opinion about what a layout is\n * keyed by.\n *\n * GENERATED by scripts/gen_barrels.py. Do not hand-edit. (0.13.0: hand-edited to\n * add chart_tiles.js \u2014 the generator is not in this repository; 0.16.1: list_tiles.js\n * and scope_picker.js, the same way; 0.17.0: figure_tile.js and tile_config_form.js.)\n *\n * 10 modules.\n */\n\nexport * from './src/tiles/chart_tiles.js';\nexport * from './src/tiles/config_schema.js';\nexport * from './src/tiles/figure_tile.js';\nexport * from './src/tiles/layout_persistence.js';\nexport * from './src/tiles/list_tiles.js';\nexport * from './src/tiles/scope_picker.js';\nexport * from './src/tiles/tile_base.js';\nexport * from './src/tiles/tile_config_form.js';\nexport * from './src/tiles/tile_grid.js';\nexport * from './src/tiles/tile_registry.js';\n"],
5
+ "mappings": "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",
6
+ "names": ["el", "el", "traces", "el", "applyTitle", "el", "getWidget"]
7
7
  }