@perspective-dev/viewer 4.5.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/dist/cdn/perspective-viewer.js +20 -1
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/intl/de.css +1 -1
  9. package/dist/css/intl/es.css +1 -1
  10. package/dist/css/intl/fr.css +1 -1
  11. package/dist/css/intl/ja.css +1 -1
  12. package/dist/css/intl/pt.css +1 -1
  13. package/dist/css/intl/zh.css +1 -1
  14. package/dist/css/intl.css +1 -1
  15. package/dist/css/monokai.css +1 -1
  16. package/dist/css/phosphor.css +1 -1
  17. package/dist/css/pro-dark.css +1 -1
  18. package/dist/css/pro.css +1 -1
  19. package/dist/css/solarized-dark.css +1 -1
  20. package/dist/css/solarized.css +1 -1
  21. package/dist/css/themes.css +1 -1
  22. package/dist/css/vaporwave.css +1 -1
  23. package/dist/esm/extensions.d.ts +22 -3
  24. package/dist/esm/perspective-viewer.d.ts +9 -0
  25. package/dist/esm/perspective-viewer.inline.js +20 -1
  26. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  27. package/dist/esm/perspective-viewer.js +20 -1
  28. package/dist/esm/perspective-viewer.js.map +4 -4
  29. package/dist/esm/plugin.d.ts +71 -5
  30. package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
  31. package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
  32. package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
  33. package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
  34. package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
  35. package/dist/esm/ts-rs/Layout.d.ts +11 -0
  36. package/dist/esm/ts-rs/Orientation.d.ts +4 -0
  37. package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
  38. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +41 -0
  39. package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
  40. package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
  41. package/dist/esm/ts-rs/ViewerConfig.d.ts +8 -2
  42. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +9 -0
  43. package/dist/esm/ts-rs/WindowAggregate.d.ts +1 -0
  44. package/dist/esm/ts-rs/WindowSort.d.ts +7 -0
  45. package/dist/esm/ts-rs/WindowSortDir.d.ts +6 -0
  46. package/dist/esm/ts-rs/WindowSpec.d.ts +46 -0
  47. package/dist/esm/ts-rs/Windows.d.ts +10 -0
  48. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
  49. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
  50. package/dist/wasm/perspective-viewer.d.ts +299 -78
  51. package/dist/wasm/perspective-viewer.js +544 -186
  52. package/dist/wasm/perspective-viewer.wasm +0 -0
  53. package/dist/wasm/perspective-viewer.wasm.d.ts +34 -26
  54. package/dist/wasm/snippets/perspective-viewer-8a8c7d5d696b43ae/inline0.js +6 -0
  55. package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline3.js → perspective-viewer-8a8c7d5d696b43ae/inline4.js} +5 -0
  56. package/package.json +3 -2
  57. package/src/css/_context_menu.css +14 -0
  58. package/src/css/column-selector.css +1 -0
  59. package/src/css/column-settings-panel.css +68 -3
  60. package/src/css/column-style.css +4 -3
  61. package/src/css/config-selector.css +22 -1
  62. package/src/css/containers/context-menu.css +107 -0
  63. package/src/css/containers/tabs.css +2 -2
  64. package/src/css/panel-tab.css +193 -0
  65. package/src/css/plugin-selector.css +7 -10
  66. package/src/css/status-bar.css +75 -81
  67. package/src/css/viewer.css +188 -70
  68. package/src/rust/components/column_dropdown.rs +40 -30
  69. package/src/rust/components/column_selector/active_column.rs +28 -45
  70. package/src/rust/components/column_selector/aggregate_selector.rs +4 -7
  71. package/src/rust/components/column_selector/column_selector_column_row.rs +73 -0
  72. package/src/rust/components/column_selector/config_selector.rs +40 -82
  73. package/src/rust/components/column_selector/expr_edit_button.rs +7 -1
  74. package/src/rust/components/column_selector/filter_column.rs +5 -15
  75. package/src/rust/components/column_selector/inactive_column.rs +11 -9
  76. package/src/rust/components/column_selector/sort_column.rs +3 -6
  77. package/src/rust/components/column_selector.rs +25 -14
  78. package/src/rust/components/column_settings_sidebar/style_tab.rs +2 -1
  79. package/src/rust/components/column_settings_sidebar/window_tab.rs +34 -0
  80. package/src/rust/components/column_settings_sidebar.rs +163 -16
  81. package/src/rust/components/containers/dragdrop_list.rs +73 -3
  82. package/src/rust/components/containers/sidebar.rs +99 -22
  83. package/src/rust/components/containers/split_panel.rs +181 -62
  84. package/src/rust/components/context_menu.rs +130 -0
  85. package/src/rust/components/editable_header.rs +2 -0
  86. package/src/rust/components/form/debug.rs +3 -0
  87. package/src/rust/components/global_filter_bar.rs +76 -0
  88. package/src/rust/components/main_panel/frame_theme.rs +186 -0
  89. package/src/rust/components/main_panel/msg.rs +62 -0
  90. package/src/rust/components/main_panel/presize.rs +220 -0
  91. package/src/rust/components/main_panel/reconcile.rs +224 -0
  92. package/src/rust/components/main_panel/render.rs +385 -0
  93. package/src/rust/components/main_panel/update.rs +184 -0
  94. package/src/rust/components/main_panel.rs +316 -71
  95. package/src/rust/components/mod.rs +5 -0
  96. package/src/rust/components/panel_menu.rs +493 -0
  97. package/src/rust/components/panel_tab.rs +510 -0
  98. package/src/rust/components/plugin_tab.rs +1 -1
  99. package/src/rust/components/portal.rs +7 -0
  100. package/src/rust/components/settings_panel.rs +13 -5
  101. package/src/rust/components/status_bar.rs +110 -178
  102. package/src/rust/components/status_indicator.rs +6 -9
  103. package/src/rust/components/style/mod.rs +5 -0
  104. package/src/rust/components/style/style_provider.rs +2 -0
  105. package/src/rust/components/viewer/filters.rs +133 -0
  106. package/src/rust/components/viewer/msg.rs +182 -0
  107. package/src/rust/components/viewer/panels.rs +326 -0
  108. package/src/rust/components/viewer/render.rs +255 -0
  109. package/src/rust/components/viewer/settings.rs +434 -0
  110. package/src/rust/components/viewer/snapshots.rs +134 -0
  111. package/src/rust/components/viewer/wiring.rs +505 -0
  112. package/src/rust/components/viewer.rs +245 -756
  113. package/src/rust/components/window_editor.rs +1013 -0
  114. package/src/rust/config/export_method.rs +1 -1
  115. package/src/rust/config/mod.rs +4 -0
  116. package/src/rust/config/options.rs +71 -0
  117. package/src/rust/config/viewer_config.rs +24 -2
  118. package/src/rust/config/workspace_config.rs +92 -0
  119. package/src/rust/custom_elements/copy_dropdown.rs +3 -1
  120. package/src/rust/custom_elements/debug_plugin.rs +20 -1
  121. package/src/rust/custom_elements/export_dropdown.rs +3 -1
  122. package/src/rust/custom_elements/viewer.rs +1015 -286
  123. package/src/rust/custom_events.rs +212 -61
  124. package/src/rust/js/mod.rs +2 -0
  125. package/src/rust/js/plugin.rs +297 -10
  126. package/src/rust/js/regular_layout.rs +258 -0
  127. package/src/rust/lib.rs +24 -2
  128. package/src/rust/presentation/column_locator.rs +16 -1
  129. package/src/rust/presentation.rs +66 -33
  130. package/src/rust/queries/columns_iter_set.rs +7 -1
  131. package/src/rust/queries/get_viewer_config.rs +29 -11
  132. package/src/rust/queries/plugin_column_styles.rs +2 -2
  133. package/src/rust/renderer/activate.rs +41 -14
  134. package/src/rust/renderer/dispatch.rs +463 -0
  135. package/src/rust/renderer/plugin_config.rs +495 -0
  136. package/src/rust/renderer/registry.rs +18 -6
  137. package/src/rust/renderer/render_timer.rs +29 -10
  138. package/src/rust/renderer.rs +384 -838
  139. package/src/rust/session/column_defaults_update.rs +26 -8
  140. package/src/rust/session/drag_drop_update.rs +18 -0
  141. package/src/rust/session/metadata.rs +66 -9
  142. package/src/rust/session/replace_expression_update.rs +1 -0
  143. package/src/rust/session/view_subscription.rs +30 -15
  144. package/src/rust/session.rs +755 -264
  145. package/src/rust/tasks/apply_global_filters.rs +89 -0
  146. package/src/rust/tasks/auto_pause.rs +171 -0
  147. package/src/rust/tasks/copy_export.rs +29 -19
  148. package/src/rust/tasks/create_panel.rs +243 -0
  149. package/src/rust/tasks/dismiss_render_warning.rs +3 -1
  150. package/src/rust/tasks/edit_expression.rs +4 -4
  151. package/src/rust/tasks/edit_window.rs +155 -0
  152. package/src/rust/tasks/eject.rs +64 -23
  153. package/src/rust/tasks/mod.rs +30 -4
  154. package/src/rust/tasks/pipeline.rs +411 -0
  155. package/src/rust/tasks/presize_panels.rs +324 -0
  156. package/src/rust/tasks/reset_all.rs +22 -12
  157. package/src/rust/tasks/resize_observer.rs +124 -87
  158. package/src/rust/tasks/restore_and_render.rs +80 -86
  159. package/src/rust/tasks/restore_panel.rs +145 -0
  160. package/src/rust/tasks/send_column_config.rs +5 -2
  161. package/src/rust/tasks/send_plugin_config.rs +5 -2
  162. package/src/rust/tasks/set_edit_mode.rs +59 -0
  163. package/src/rust/tasks/sync_update_panels.rs +152 -0
  164. package/src/rust/tasks/table_lifecycle.rs +158 -0
  165. package/src/rust/tasks/update_theme.rs +56 -12
  166. package/src/rust/utils/browser/dragdrop.rs +12 -0
  167. package/src/rust/utils/browser/tests/debounce.rs +49 -0
  168. package/src/rust/utils/completion.rs +56 -0
  169. package/src/rust/utils/custom_element.rs +5 -0
  170. package/src/rust/utils/debounce.rs +189 -17
  171. package/src/rust/utils/mod.rs +6 -0
  172. package/src/rust/utils/pending_effects.rs +62 -0
  173. package/src/rust/utils/spawn.rs +33 -0
  174. package/src/rust/utils/weak_scope.rs +0 -10
  175. package/src/rust/workspace.rs +846 -0
  176. package/src/svg/active-indicator.svg +3 -0
  177. package/src/svg/pin-icon.svg +5 -0
  178. package/src/themes/botanical.css +5 -2
  179. package/src/themes/defaults.css +54 -2
  180. package/src/themes/dracula.css +6 -3
  181. package/src/themes/gruvbox-dark.css +5 -2
  182. package/src/themes/gruvbox.css +5 -2
  183. package/src/themes/icons.css +5 -2
  184. package/src/themes/intl/de.css +7 -0
  185. package/src/themes/intl/es.css +7 -0
  186. package/src/themes/intl/fr.css +7 -0
  187. package/src/themes/intl/ja.css +7 -0
  188. package/src/themes/intl/pt.css +7 -0
  189. package/src/themes/intl/zh.css +7 -0
  190. package/src/themes/intl.css +10 -1
  191. package/src/themes/monokai.css +5 -2
  192. package/src/themes/phosphor.css +5 -2
  193. package/src/themes/pro-dark.css +5 -2
  194. package/src/themes/pro.css +2 -1
  195. package/src/themes/solarized-dark.css +5 -2
  196. package/src/themes/solarized.css +5 -2
  197. package/src/themes/vaporwave.css +5 -2
  198. package/src/ts/bootstrap.ts +8 -7
  199. package/src/ts/extensions.ts +30 -2
  200. package/src/ts/perspective-viewer.ts +10 -0
  201. package/src/ts/plugin.ts +72 -5
  202. package/src/ts/ts-rs/ClientOptions.ts +7 -0
  203. package/src/ts/ts-rs/ExportMethod.ts +3 -0
  204. package/src/ts/ts-rs/ExportOptions.ts +8 -0
  205. package/src/ts/ts-rs/GetClientOptions.ts +7 -0
  206. package/src/ts/ts-rs/GetTableOptions.ts +7 -0
  207. package/src/ts/ts-rs/Layout.ts +9 -0
  208. package/src/ts/ts-rs/Orientation.ts +6 -0
  209. package/src/ts/ts-rs/PanelOptions.ts +7 -0
  210. package/src/ts/ts-rs/PanelViewerConfig.ts +16 -0
  211. package/src/ts/ts-rs/SplitLayout.ts +5 -0
  212. package/src/ts/ts-rs/TabLayout.ts +11 -0
  213. package/src/ts/ts-rs/ViewerConfig.ts +7 -2
  214. package/src/ts/ts-rs/ViewerConfigUpdate.ts +9 -0
  215. package/src/ts/ts-rs/WindowAggregate.ts +3 -0
  216. package/src/ts/ts-rs/WindowSort.ts +9 -0
  217. package/src/ts/ts-rs/WindowSortDir.ts +8 -0
  218. package/src/ts/ts-rs/WindowSpec.ts +46 -0
  219. package/src/ts/ts-rs/Windows.ts +10 -0
  220. package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
  221. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
  222. package/src/rust/tasks/intersection_observer.rs +0 -98
  223. package/src/rust/tasks/update_and_render.rs +0 -110
  224. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline0.js → perspective-viewer-8a8c7d5d696b43ae/inline1.js} +0 -0
  225. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline1.js → perspective-viewer-8a8c7d5d696b43ae/inline2.js} +0 -0
  226. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline2.js → perspective-viewer-8a8c7d5d696b43ae/inline3.js} +0 -0
  227. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline4.js → perspective-viewer-8a8c7d5d696b43ae/inline5.js} +0 -0
@@ -15,6 +15,36 @@ import { PluginStaticConfig } from "./ts-rs/PluginStaticConfig.js";
15
15
  * level (if packaged as a library), or during application init to ensure global
16
16
  * availability of a plugin.
17
17
  *
18
+ * ## Dispatch contract
19
+ *
20
+ * The host dispatches each method for exactly one reason, and never
21
+ * defensively — implementations may rely on these meanings:
22
+ *
23
+ * - `draw(view)` — `view` is NEW to this plugin: a new engine `View` was
24
+ * constructed, or this plugin was freshly selected and owes its first
25
+ * render. Safe to reset zoom/scroll/selection state.
26
+ * - `update(view)` — same `View`, but a plugin-visible input genuinely
27
+ * changed: new data (`View.on_update`), an effective view-config delta
28
+ * without a rebuild, a *changed* plugin/columns config just delivered
29
+ * via `restore()`, changed CSS just applied via `restyle()`, a
30
+ * render-limits change, or an explicit public `viewer.restore()` call
31
+ * (the no-op-restore refresh affordance). Host-internal operations that
32
+ * change none of these dispatch nothing.
33
+ * - `resize(view)` — geometry or visibility changed (including panel
34
+ * activation); repaint from retained state, no data or CSS re-read.
35
+ * - `restyle()` — the effective theme genuinely changed; when a
36
+ * `draw`/`update` is part of the same operation, `restyle()` is called
37
+ * immediately BEFORE it, so one render pass paints in the new theme.
38
+ * - `restore()`/`save()` — state transfer only. Plugins must NOT render
39
+ * from `restore()` (a changed restore is always followed by exactly one
40
+ * `update`) and must NOT call host APIs from inside it — a
41
+ * `restore()` echo re-enters the host's public surface and forces
42
+ * a redundant render (the classic double-render-on-load bug).
43
+ *
44
+ * Rendering methods (`draw`, `update`, `resize`, `render`, `clear`) and
45
+ * `delete` are serialized per element — the host never overlaps them, and
46
+ * each call runs to completion before the next begins.
47
+ *
18
48
  * @example
19
49
  * ```javascript
20
50
  * const BasePlugin = customElements.get("perspective-viewer-plugin");
@@ -53,6 +83,14 @@ export interface IPerspectiveViewerPlugin {
53
83
  * provision to cancel a render in progress per se, calling a method on
54
84
  * a `View` which has been deleted will throw an exception.
55
85
  *
86
+ * The host invokes `draw` ONLY when `view` is NEW to this plugin — a
87
+ * new engine `View` was constructed for a config change, or this plugin
88
+ * element was freshly selected and owes its first render of the bound
89
+ * `View` — so implementations may treat it as "new data shape" and
90
+ * reset zoom/scroll/selection-domain state. Repaints of the same
91
+ * `View` arrive as `update()` (data or style refresh) or `resize()`
92
+ * (geometry/chrome), never `draw()`.
93
+ *
56
94
  * @example
57
95
  * ```
58
96
  * async draw(view: perspective.View): Promise<void> {
@@ -63,9 +101,9 @@ export interface IPerspectiveViewerPlugin {
63
101
  */
64
102
  draw(view: View): Promise<void>;
65
103
  /**
66
- * Draw under the assumption that the `ViewConfig` has not changed since
67
- * the previous call to `draw()`, but the underlying data has. Defaults to
68
- * dispatch to `draw()`.
104
+ * Draw under the assumption that the `View` has not changed since the
105
+ * previous call to `draw()`, but some plugin-visible input has.
106
+ * Defaults to dispatch to `draw()`.
69
107
  *
70
108
  * @example
71
109
  * ```javascript
@@ -91,18 +129,46 @@ export interface IPerspectiveViewerPlugin {
91
129
  clear(): Promise<void>;
92
130
  /**
93
131
  * Like `update()`, but for when the dimensions of the plugin have changed
94
- * and the underlying data has not.
132
+ * and the underlying data has not — a repaint from retained state,
133
+ * invoked ONLY when geometry or visibility changed: box resizes,
134
+ * presize sweeps, and the panel-ACTIVATION chrome nudge (multi-panel),
135
+ * so implementations should repaint activation-dependent chrome here
136
+ * and no-op while hidden (`offsetParent == null`).
95
137
  */
96
138
  resize(view: View): Promise<void>;
97
139
  /**
98
140
  * Notify the plugin that the style environment has changed. Useful for
99
- * plugins which read CSS styles via `window.getComputedStyle()`.
141
+ * plugins which read CSS styles via `window.getComputedStyle()` — this
142
+ * is the ONLY point at which a plugin is expected to (re-)read them
143
+ * (besides its first `draw()`), so implementations may cache computed
144
+ * styles between `restyle()` calls.
100
145
  */
101
146
  restyle(): void;
102
147
  /**
103
148
  * Restore this plugin to a state previously returned by `save()`.
149
+ *
150
+ * State transfer ONLY — implementations must not render from
151
+ * `restore()` (the host follows a restore that genuinely changed
152
+ * plugin state with exactly one `update()` in the same serialized
153
+ * sequence), and must not call host `<perspective-viewer>` APIs from
154
+ * inside it: an echoed `restore()` re-enters the host's public
155
+ * surface where it is indistinguishable from a user call and forces a
156
+ * redundant render. Host API calls to persist plugin state belong to
157
+ * genuine user-gesture handlers (e.g. a toolbar click), never to the
158
+ * `restore()` delivery path.
104
159
  */
105
160
  restore(config: any): void;
161
+ /**
162
+ * OPTIONAL — clear any visible user selection state (highlighted rows,
163
+ * pinned tooltips) WITHOUT emitting selection events. The host
164
+ * `<perspective-viewer>` invokes this when an element-level global
165
+ * filter contributed by this plugin's selection is removed from the
166
+ * global filter bar, so the selection visual can't outlive the filter
167
+ * it produced. Called under the host's per-panel render serialization
168
+ * (like `draw`), so implementations may redraw. Plugins without a
169
+ * selection UI may omit it.
170
+ */
171
+ deselect?(): Promise<void>;
106
172
  /**
107
173
  * Free any resources acquired by this plugin and prepare to be deleted.
108
174
  */
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The `eject` argument: the loaded client to remove by name; the active
3
+ * panel's client when omitted.
4
+ */
5
+ export type ClientOptions = {
6
+ client?: string;
7
+ };
@@ -0,0 +1 @@
1
+ export type ExportMethod = "csv" | "csv-all" | "csv-selected" | "json" | "json-all" | "json-selected" | "ndjson" | "ndjson-all" | "ndjson-selected" | "html" | "plugin" | "arrow" | "arrow-selected" | "arrow-all" | "json-config";
@@ -0,0 +1,9 @@
1
+ import type { ExportMethod } from "./ExportMethod.js";
2
+ /**
3
+ * The `download` / `export` / `copy` argument: the `ExportMethod` and target
4
+ * panel.
5
+ */
6
+ export type ExportOptions = {
7
+ method?: ExportMethod;
8
+ panel?: string;
9
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The `getClient` argument: whether to `wait` for a `Client`, and the target
3
+ * panel.
4
+ */
5
+ export type GetClientOptions = {
6
+ wait?: boolean;
7
+ panel?: string;
8
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The `getTable` argument: whether to `wait` for a `Table`, and the target
3
+ * panel.
4
+ */
5
+ export type GetTableOptions = {
6
+ wait?: boolean;
7
+ panel?: string;
8
+ };
@@ -0,0 +1,11 @@
1
+ import type { SplitLayout } from "./SplitLayout.js";
2
+ import type { TabLayout } from "./TabLayout.js";
3
+ /**
4
+ * A serde mirror of `regular-layout`'s serialized layout tree, as returned by
5
+ * [`RegularLayout::save`] and accepted by [`RegularLayout::restore`].
6
+ */
7
+ export type Layout = {
8
+ "type": "split-layout";
9
+ } & SplitLayout | {
10
+ "type": "tab-layout";
11
+ } & TabLayout;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * The orientation of a [`SplitLayout`].
3
+ */
4
+ export type Orientation = "horizontal" | "vertical";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Selects the target panel of a panel-scoped `<perspective-viewer>` method;
3
+ * the active panel when `panel` is omitted.
4
+ */
5
+ export type PanelOptions = {
6
+ panel?: string;
7
+ };
@@ -0,0 +1,41 @@
1
+ import type { Aggregate } from "./Aggregate.js";
2
+ import type { Expressions } from "./Expressions.js";
3
+ import type { Filter } from "./Filter.js";
4
+ import type { FilterReducer } from "./FilterReducer.js";
5
+ import type { GroupRollupMode } from "./GroupRollupMode.js";
6
+ import type { Sort } from "./Sort.js";
7
+ import type { Windows } from "./Windows.js";
8
+ import type { JsonValue } from "./serde_json/JsonValue.js";
9
+ /**
10
+ * The per-panel state of a [`ViewerConfig`] — everything except the
11
+ * element-level `settings` flag. This is the `panels` entry type of the
12
+ * whole-element config format.
13
+ */
14
+ export type PanelViewerConfig<V = string> = {
15
+ version: V;
16
+ columns_config: {
17
+ [key in string]?: {
18
+ [key in string]?: JsonValue;
19
+ };
20
+ };
21
+ plugin: string;
22
+ plugin_config: {
23
+ [key in string]?: JsonValue;
24
+ };
25
+ table: string | null;
26
+ theme: string | null;
27
+ title: string | null;
28
+ group_by: Array<string>;
29
+ split_by: Array<string>;
30
+ sort: Array<Sort>;
31
+ filter: Array<Filter>;
32
+ group_rollup_mode: GroupRollupMode;
33
+ filter_op?: FilterReducer;
34
+ expressions: Expressions;
35
+ windows?: Windows;
36
+ columns: Array<string | null>;
37
+ aggregates: {
38
+ [key in string]?: Aggregate;
39
+ };
40
+ group_by_depth?: number | null;
41
+ };
@@ -0,0 +1,7 @@
1
+ import type { Layout } from "./Layout.js";
2
+ import type { Orientation } from "./Orientation.js";
3
+ export type SplitLayout = {
4
+ children: Array<Layout>;
5
+ sizes: Array<number>;
6
+ orientation: Orientation;
7
+ };
@@ -0,0 +1,10 @@
1
+ export type TabLayout = {
2
+ /**
3
+ * Panel ids (slot names) in this stack.
4
+ */
5
+ tabs: Array<string>;
6
+ /**
7
+ * Index of the selected tab within `tabs`.
8
+ */
9
+ selected?: number;
10
+ };
@@ -4,12 +4,18 @@ import type { Filter } from "./Filter.js";
4
4
  import type { FilterReducer } from "./FilterReducer.js";
5
5
  import type { GroupRollupMode } from "./GroupRollupMode.js";
6
6
  import type { Sort } from "./Sort.js";
7
+ import type { Windows } from "./Windows.js";
7
8
  import type { JsonValue } from "./serde_json/JsonValue.js";
8
9
  /**
9
10
  * The state of an entire `custom_elements::PerspectiveViewerElement` component
10
- * and its `Plugin`.
11
+ * and its `Plugin`: the element-level `settings` flag plus the per-panel
12
+ * [`PanelViewerConfig`]. The split exists so the whole-element config format
13
+ * can serialize panel entries *without* a `settings` key (it is element-level
14
+ * state there, carried by the top-level `active` field instead), while the
15
+ * single-panel format flattens back to the legacy shape.
11
16
  */
12
17
  export type ViewerConfig<V = string> = {
18
+ settings: boolean;
13
19
  version: V;
14
20
  columns_config: {
15
21
  [key in string]?: {
@@ -20,7 +26,6 @@ export type ViewerConfig<V = string> = {
20
26
  plugin_config: {
21
27
  [key in string]?: JsonValue;
22
28
  };
23
- settings: boolean;
24
29
  table: string | null;
25
30
  theme: string | null;
26
31
  title: string | null;
@@ -31,6 +36,7 @@ export type ViewerConfig<V = string> = {
31
36
  group_rollup_mode: GroupRollupMode;
32
37
  filter_op?: FilterReducer;
33
38
  expressions: Expressions;
39
+ windows?: Windows;
34
40
  columns: Array<string | null>;
35
41
  aggregates: {
36
42
  [key in string]?: Aggregate;
@@ -5,6 +5,7 @@ import type { FilterReducer } from "./FilterReducer.js";
5
5
  import type { GroupRollupMode } from "./GroupRollupMode.js";
6
6
  import type { OptionalUpdate } from "./OptionalUpdate.js";
7
7
  import type { Sort } from "./Sort.js";
8
+ import type { Windows } from "./Windows.js";
8
9
  import type { JsonValue } from "./serde_json/JsonValue.js";
9
10
  export type ViewerConfigUpdate = {
10
11
  version?: OptionalUpdate<string>;
@@ -86,6 +87,14 @@ export type ViewerConfigUpdate = {
86
87
  * panel.
87
88
  */
88
89
  expressions?: Expressions;
90
+ /**
91
+ * The `windows` property declares ordered, partitioned rolling
92
+ * computations (moving aggregates, cumulative sums) as _new_ columns
93
+ * keyed by output alias (`{"name": {...spec}}`, symmetric with
94
+ * `expressions`), analogous to SQL window functions. See
95
+ * [`crate::config::WindowSpec`].
96
+ */
97
+ windows?: Windows;
89
98
  /**
90
99
  * Aggregates perform a calculation over an entire column, and are
91
100
  * displayed when one or more [Group By](#group-by) are applied to the
@@ -0,0 +1 @@
1
+ export type WindowAggregate = "sum" | "avg" | "count" | "min" | "max" | "stddev" | "var" | "first" | "last" | "lag" | "lead" | "diff" | "rate" | "ema";
@@ -0,0 +1,7 @@
1
+ import type { WindowSortDir } from "./WindowSortDir.js";
2
+ /**
3
+ * The `Table` column which orders each partition, with its direction -
4
+ * serialized as a two-element array (`["ts", "desc"]`), symmetric with the
5
+ * `ViewConfig`'s `sort` field.
6
+ */
7
+ export type WindowSort = [string, WindowSortDir];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A window's order direction. A dedicated two-variant enum rather than
3
+ * [`crate::config::SortDir`] - the column-sort extras (`col asc`, `abs`,
4
+ * `none`) are meaningless inside a window frame and unrepresentable here.
5
+ */
6
+ export type WindowSortDir = "asc" | "desc";
@@ -0,0 +1,46 @@
1
+ import type { WindowAggregate } from "./WindowAggregate.js";
2
+ import type { WindowSort } from "./WindowSort.js";
3
+ /**
4
+ * The serialized form of [`WindowSpec`].
5
+ */
6
+ export type WindowSpec = {
7
+ /**
8
+ * The input column - either a real `Table` column or an expression
9
+ * alias from the same `ViewConfig`.
10
+ */
11
+ column: string;
12
+ aggregate: WindowAggregate;
13
+ /**
14
+ * Columns whose distinct value tuples partition the rows; empty
15
+ * partitions the whole `Table` as one group.
16
+ */
17
+ partition_by?: Array<string>;
18
+ /**
19
+ * The `Table` column which orders each partition, and the direction.
20
+ */
21
+ order_by?: WindowSort | null;
22
+ /**
23
+ * A frame of the `rows` preceding each row, plus the row itself.
24
+ * Mutually exclusive with `range` and `cumulative`.
25
+ */
26
+ rows?: number | null;
27
+ /**
28
+ * A frame of the rows whose `order_by` value lies within `range` of
29
+ * each row's, requiring a numeric or temporal `order_by`. Mutually
30
+ * exclusive with `rows` and `cumulative`.
31
+ */
32
+ range?: number | null;
33
+ /**
34
+ * `true` frames all rows from the partition start through each row.
35
+ * Default can be omitted.
36
+ */
37
+ cumulative?: boolean | null;
38
+ /**
39
+ * Row offset for `lag`/`lead` (default 1).
40
+ */
41
+ offset?: number | null;
42
+ /**
43
+ * Smoothing factor in `(0, 1]` for `ema`.
44
+ */
45
+ alpha?: number | null;
46
+ };
@@ -0,0 +1,10 @@
1
+ import type { WindowSpec } from "./WindowSpec.js";
2
+ /**
3
+ * The window columns of a `ViewConfig`, keyed by output column alias -
4
+ * symmetric with `expressions` (`{"name": {...spec}}`). An alias must not
5
+ * collide with a `Table` column, expression alias, or another window's
6
+ * key.
7
+ */
8
+ export type Windows = {
9
+ [key in string]?: WindowSpec;
10
+ };
@@ -0,0 +1,40 @@
1
+ import type { Filter } from "./Filter.js";
2
+ import type { Layout } from "./Layout.js";
3
+ import type { PanelViewerConfig } from "./PanelViewerConfig.js";
4
+ /**
5
+ * The whole-element config format (`{version, active?, layout, panels}`) —
6
+ * the multi-panel counterpart of the single-panel [`ViewerConfig`] — as
7
+ * emitted by [`PerspectiveViewerElement::save`].
8
+ *
9
+ * - `panels` entries are [`PanelViewerConfig`]s: per-panel state only, no
10
+ * `settings` key (element-level state).
11
+ * - `active` names the panel targeted by the *open* settings sidebar; it is
12
+ * omitted when the sidebar is closed.
13
+ */
14
+ export type WorkspaceConfig = {
15
+ version: string;
16
+ active?: string;
17
+ layout: Layout | null;
18
+ /**
19
+ * `BTreeMap` (not `HashMap`) so `save()` serializes panels in a
20
+ * DETERMINISTIC (sorted) key order — a fresh `HashMap` per call
21
+ * iterates in a per-instance random order, which made consecutive
22
+ * `save()` outputs byte-unstable.
23
+ */
24
+ panels: {
25
+ [key in string]?: PanelViewerConfig<string>;
26
+ };
27
+ /**
28
+ * The element-level global (master/detail cross-) filters. A transient
29
+ * overlay on every detail panel's view — persisted here, never in a
30
+ * per-panel entry. Omitted when empty.
31
+ */
32
+ global_filters?: Array<Filter>;
33
+ /**
34
+ * The MASTER (filter-source) panels' ids, referencing `panels` keys.
35
+ * Roles are layout state (like the panel arrangement), so they persist;
36
+ * which master contributed which clause does not — restored
37
+ * `global_filters` are one unattributed bucket. Omitted when empty.
38
+ */
39
+ masters?: Array<string>;
40
+ };
@@ -0,0 +1,28 @@
1
+ import type { Filter } from "./Filter.js";
2
+ import type { Layout } from "./Layout.js";
3
+ import type { ViewerConfigUpdate } from "./ViewerConfigUpdate.js";
4
+ /**
5
+ * The parse target of a whole-element config in
6
+ * [`PerspectiveViewerElement::restore`]. Mirrors [`WorkspaceConfig`],
7
+ * but `panels` entries are full [`ViewerConfigUpdate`]s so a stray per-panel
8
+ * `settings` can be detected (warned, then ignored — `create_panel` strips
9
+ * it).
10
+ */
11
+ export type WorkspaceConfigUpdate = {
12
+ active?: string;
13
+ layout?: Layout;
14
+ panels: {
15
+ [key in string]?: ViewerConfigUpdate;
16
+ };
17
+ /**
18
+ * The element-level global (master/detail cross-) filters to re-apply as
19
+ * a transient overlay on every DETAIL panel. Restored as one
20
+ * unattributed bucket: the next selection on any master replaces it.
21
+ */
22
+ global_filters?: Array<Filter>;
23
+ /**
24
+ * The master (filter-source) panels, by saved `panels` key. An id not in
25
+ * `panels` warns and is dropped.
26
+ */
27
+ masters?: Array<string>;
28
+ };