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, ViewerConfigUpdate};
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::restore`]. Mirrors [`WorkspaceConfig`],
63/// but `panels` entries are full [`ViewerConfigUpdate`]s so a stray per-panel
64/// `settings` can be detected (warned, then ignored — `create_panel` strips
65/// it).
66#[derive(serde::Deserialize, ts_rs::TS)]
67pub struct WorkspaceConfigUpdate {
68 #[serde(default)]
69 #[ts(optional)]
70 pub active: Option<String>,
71
72 #[serde(default)]
73 #[ts(optional)]
74 pub layout: Option<crate::js::Layout>,
75
76 pub panels: BTreeMap<String, ViewerConfigUpdate>,
77
78 /// The element-level global (master/detail cross-) filters to re-apply as
79 /// a transient overlay on every DETAIL panel. Restored as one
80 /// unattributed bucket: the next selection on any master replaces it.
81 #[serde(default)]
82 #[ts(as = "Option<_>")]
83 #[ts(optional)]
84 pub global_filters: Vec<Filter>,
85
86 /// The master (filter-source) panels, by saved `panels` key. An id not in
87 /// `panels` warns and is dropped.
88 #[serde(default)]
89 #[ts(as = "Option<_>")]
90 #[ts(optional)]
91 pub masters: Vec<String>,
92}