perspective_viewer/config/workspace_config.rs
1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors. ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::collections::BTreeMap;
14
15use perspective_client::config::Filter;
16
17use crate::config::{PanelViewerConfig, ViewerConfigInitial};
18
19/// The whole-element config format (`{version, active?, layout, panels}`) —
20/// the multi-panel counterpart of the single-panel [`ViewerConfig`] — as
21/// emitted by [`PerspectiveViewerElement::save`].
22///
23/// - `panels` entries are [`PanelViewerConfig`]s: per-panel state only, no
24/// `settings` key (element-level state).
25/// - `active` names the panel targeted by the *open* settings sidebar; it is
26/// omitted when the sidebar is closed.
27#[derive(serde::Serialize, ts_rs::TS)]
28pub struct WorkspaceConfig {
29 pub version: String,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
32 #[ts(optional)]
33 pub active: Option<String>,
34
35 pub layout: Option<crate::js::Layout>,
36
37 /// `BTreeMap` (not `HashMap`) so `save()` serializes panels in a
38 /// DETERMINISTIC (sorted) key order — a fresh `HashMap` per call
39 /// iterates in a per-instance random order, which made consecutive
40 /// `save()` outputs byte-unstable.
41 pub panels: BTreeMap<String, PanelViewerConfig>,
42
43 /// The element-level global (master/detail cross-) filters. A transient
44 /// overlay on every detail panel's view — persisted here, never in a
45 /// per-panel entry. Omitted when empty.
46 #[serde(skip_serializing_if = "Vec::is_empty")]
47 #[ts(as = "Option<_>")]
48 #[ts(optional)]
49 pub global_filters: Vec<Filter>,
50
51 /// The MASTER (filter-source) panels' ids, referencing `panels` keys.
52 /// Roles are layout state (like the panel arrangement), so they persist;
53 /// which master contributed which clause does not — restored
54 /// `global_filters` are one unattributed bucket. Omitted when empty.
55 #[serde(skip_serializing_if = "Vec::is_empty")]
56 #[ts(as = "Option<_>")]
57 #[ts(optional)]
58 pub masters: Vec<String>,
59}
60
61/// The parse target of a whole-element config in
62/// [`PerspectiveViewerElement::restoreWorkspace`]. Mirrors
63/// [`WorkspaceConfig`], but `panels` entries are [`ViewerConfigInitial`]s —
64/// every entry creates a NEW panel, so `table` is required by type (a
65/// stray per-panel `settings` key is ignored; it is element-level state,
66/// carried by the top-level `active` field).
67#[derive(serde::Deserialize, ts_rs::TS)]
68pub struct WorkspaceConfigUpdate {
69 #[serde(default)]
70 #[ts(optional)]
71 pub active: Option<String>,
72
73 #[serde(default)]
74 #[ts(optional)]
75 pub layout: Option<crate::js::Layout>,
76
77 pub panels: BTreeMap<String, ViewerConfigInitial>,
78
79 /// The element-level global (master/detail cross-) filters to re-apply as
80 /// a transient overlay on every DETAIL panel. Restored as one
81 /// unattributed bucket: the next selection on any master replaces it.
82 #[serde(default)]
83 #[ts(as = "Option<_>")]
84 #[ts(optional)]
85 pub global_filters: Vec<Filter>,
86
87 /// The master (filter-source) panels, by saved `panels` key. An id not in
88 /// `panels` warns and is dropped.
89 #[serde(default)]
90 #[ts(as = "Option<_>")]
91 #[ts(optional)]
92 pub masters: Vec<String>,
93}