Add typed data contract editing and bounded dictionary views

This commit is contained in:
2026-09-06 03:58:43 +03:00
parent 7426c03f4e
commit b403039d00
14 changed files with 2956 additions and 137 deletions
+82
View File
@@ -115,6 +115,7 @@ pub enum Message {
BrowseGroup(crate::explorer::Group),
ExplorerPage(usize),
CreateKind(Kind),
Data(crate::data_view::Event),
Add(bool),
AddRelation,
PortAction(crate::port_workflow::Action),
@@ -127,6 +128,8 @@ pub enum Message {
Field(String, String),
FieldText(String, text_editor::Action),
FieldShape(String, Value),
FieldAppend(String, Value),
FieldValuePath(String, crate::data_values::FieldPathKey),
FieldVariant(String, Value),
FieldArray(String, Option<usize>, i32),
Apply,
@@ -204,6 +207,7 @@ pub struct App {
pub page: Page,
pub guide: crate::guide::State,
pub behavior: crate::behavior::State,
pub data_state: crate::data_view::State,
pub inspector_tab: crate::navigation::InspectorTab,
pub layer: Layer,
pub selected: Id,
@@ -292,6 +296,7 @@ impl App {
page: Page::Diagram,
guide: crate::guide::State::default(),
behavior: Default::default(),
data_state: Default::default(),
inspector_tab: Default::default(),
layer,
selected,
@@ -764,6 +769,8 @@ impl App {
Message::Field(..)
| Message::FieldText(..)
| Message::FieldShape(..)
| Message::FieldAppend(..)
| Message::FieldValuePath(..)
| Message::FieldVariant(..)
| Message::FieldArray(..)
| Message::ElementKind(_)
@@ -896,6 +903,7 @@ impl App {
self.connection = None;
}
if previous_layer != self.layer {
self.data_state = Default::default();
self.explorer_index = crate::explorer::Index::new(self.project(), self.layer);
self.explorer_focus = None;
self.explorer_group = None;
@@ -1124,6 +1132,20 @@ impl App {
self.status = e;
}
}
Message::FieldAppend(path, value) => {
if let Some(draft) = &mut self.draft
&& let Err(error) = draft.append(&path, value)
{
self.status = error;
}
}
Message::FieldValuePath(path, key) => {
if let Some(draft) = &mut self.draft
&& let Err(error) = draft.value_path(&path, key)
{
self.status = error;
}
}
Message::FieldVariant(path, value) => {
if let Some(d) = &mut self.draft {
let result = d.materialize().and_then(|current| {
@@ -1384,6 +1406,19 @@ impl App {
self.fit();
}
}
Message::Data(event) => {
if self.data_state.update(&event) {
return Task::none();
}
if self.apply() {
match crate::data_view::command(self.project(), self.layer, event) {
Ok(command) => {
self.execute(command);
}
Err(error) => self.status = error,
}
}
}
Message::CreateKind(kind) => self.create_kind = kind,
Message::Add(child) => {
if self.apply() {
@@ -3847,3 +3882,50 @@ mod lint_tests {
assert!(app.project().elements.is_empty());
}
}
#[cfg(test)]
mod data_paging_lifecycle_tests {
use super::*;
#[test]
fn paging_preserves_same_context_and_resets_on_layer_or_document_replacement() {
let mut p = Project::empty();
let mut oa = None;
for layer in [Layer::Oa, Layer::Sa] {
for index in 0..70 {
let id = p
.add_element(
Kind::Interface,
layer,
&format!("Interface {layer} {index}"),
None,
)
.unwrap();
if layer == Layer::Oa {
oa = Some(id);
}
}
}
let mut app = App::with_project(p.clone());
let page = Message::Data(crate::data_view::Event::Page {
section: crate::data_view::Section::Catalog,
owner: None,
page: 2,
});
let _ = app.update(Message::Page(Page::Data));
let _ = app.update(page.clone());
let retained = app.data_state.clone();
let _ = app.update(Message::Page(Page::Catalog));
let _ = app.update(Message::Page(Page::Data));
let _ = app.update(Message::Layer(Layer::Oa));
assert_eq!(app.data_state, retained);
let _ = app.update(Message::Layer(Layer::Sa));
assert_eq!(app.data_state, crate::data_view::State::default());
let _ = app.update(page.clone());
let _ = app.update(Message::Select(oa.unwrap()));
assert_eq!(app.layer, Layer::Oa);
assert_eq!(app.data_state, crate::data_view::State::default());
let _ = app.update(page);
app.reset(p, None);
assert_eq!(app.data_state, crate::data_view::State::default());
}
}