Integrate release recovery, semantic review, coverage and Windows packaging
This commit is contained in:
@@ -11,17 +11,24 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
mod constructors;
|
||||
mod history;
|
||||
mod keyed;
|
||||
mod keyed_rows;
|
||||
mod message_kind;
|
||||
mod ordered;
|
||||
mod recovery;
|
||||
mod scalar;
|
||||
mod view;
|
||||
pub(crate) use view::summary;
|
||||
#[cfg(test)]
|
||||
mod constructor_tests;
|
||||
#[cfg(test)]
|
||||
mod keyed_rows_tests;
|
||||
#[cfg(test)]
|
||||
mod keyed_tests;
|
||||
#[cfg(test)]
|
||||
mod message_kind_tests;
|
||||
#[cfg(test)]
|
||||
mod ordered_tests;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -65,9 +72,19 @@ pub enum Event {
|
||||
EditPair(FacetSelector),
|
||||
StageMember,
|
||||
DropStaged(FacetSelector),
|
||||
AnnotationAddress(Layer, Option<crate::data_values::FieldPathKey>),
|
||||
AnnotationBrowse(Layer, Option<crate::data_values::FieldPathKey>, usize),
|
||||
#[cfg(test)]
|
||||
RowExpression(FacetSelector, String),
|
||||
RowText(FacetSelector, text_editor::Action),
|
||||
RowLocal(FacetSelector, Choice),
|
||||
OrderMove(OrderedCollection, usize, i32),
|
||||
OrderReconcile(OrderedCollection),
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
base_identity: Id,
|
||||
base_fingerprint: String,
|
||||
pub anchor: Id,
|
||||
pub trace: Option<Id>,
|
||||
pub direction: TransitionDirection,
|
||||
@@ -78,6 +95,10 @@ pub struct State {
|
||||
pub resets: BTreeSet<FacetSelector>,
|
||||
pub staged: BTreeSet<FacetSelector>,
|
||||
pub presence: BTreeMap<FacetSelector, bool>,
|
||||
pub row_drafts: BTreeMap<FacetSelector, keyed_rows::RowDraft>,
|
||||
pub order_drafts: BTreeMap<OrderedCollection, Vec<Id>>,
|
||||
pub annotation_oa: keyed_rows::AddressDraft,
|
||||
pub annotation_sa: keyed_rows::AddressDraft,
|
||||
pub member_family: keyed::Family,
|
||||
pub member_oa: Option<Choice>,
|
||||
pub member_sa: Option<Choice>,
|
||||
@@ -118,6 +139,8 @@ impl State {
|
||||
.map(|t| t.id)
|
||||
.or_else(|| (choices.len() == 1).then(|| choices[0].id));
|
||||
let mut state = Self {
|
||||
base_identity: project.id,
|
||||
base_fingerprint: project_fingerprint(project),
|
||||
anchor,
|
||||
trace,
|
||||
direction: if layer == Layer::Oa {
|
||||
@@ -132,6 +155,10 @@ impl State {
|
||||
resets: BTreeSet::new(),
|
||||
staged: BTreeSet::new(),
|
||||
presence: BTreeMap::new(),
|
||||
row_drafts: BTreeMap::new(),
|
||||
order_drafts: BTreeMap::new(),
|
||||
annotation_oa: Default::default(),
|
||||
annotation_sa: Default::default(),
|
||||
member_family: keyed::Family::Literal,
|
||||
member_oa: None,
|
||||
member_sa: None,
|
||||
@@ -169,6 +196,10 @@ impl State {
|
||||
self.resets.clear();
|
||||
self.staged.clear();
|
||||
self.presence.clear();
|
||||
self.row_drafts.clear();
|
||||
self.order_drafts.clear();
|
||||
self.annotation_oa = Default::default();
|
||||
self.annotation_sa = Default::default();
|
||||
self.member_oa = None;
|
||||
self.member_sa = None;
|
||||
self.literal.clear();
|
||||
@@ -227,6 +258,7 @@ impl State {
|
||||
}
|
||||
Event::Select(facet) => {
|
||||
self.selected = Some(facet);
|
||||
self.tab = Tab::Facts;
|
||||
replan = false;
|
||||
Ok(())
|
||||
}
|
||||
@@ -238,7 +270,16 @@ impl State {
|
||||
{
|
||||
Err("This fact needs the structured review workflow; its history remains unchanged.".into())
|
||||
} else {
|
||||
if keyed::supported(&facet) {
|
||||
if let FacetSelector::Order(which) = facet
|
||||
&& decision == SemanticDecision::Candidate
|
||||
{
|
||||
if let Err(error) = self.initialize_order(project, which) {
|
||||
self.error = Some(error);
|
||||
return;
|
||||
}
|
||||
} else if keyed_rows::supported(&facet) {
|
||||
self.initialize_row(project, &facet);
|
||||
} else if keyed::supported(&facet) {
|
||||
let target_presence = self
|
||||
.effective_trace(project)
|
||||
.and_then(|t| capture_facet(project, t.oa, t.sa, &facet).ok())
|
||||
@@ -332,6 +373,8 @@ impl State {
|
||||
return;
|
||||
}
|
||||
Event::Preview => Ok(()),
|
||||
Event::OrderMove(which, index, delta) => self.move_order(which, index, delta),
|
||||
Event::OrderReconcile(which) => self.reconcile_order(project, which),
|
||||
Event::Reset(facet, reset) => self.reset_history(project, facet, reset),
|
||||
Event::Presence(facet, present) => {
|
||||
if keyed::supported(&facet)
|
||||
@@ -383,6 +426,30 @@ impl State {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Event::AnnotationAddress(layer, key) => {
|
||||
self.annotation_address_mut(layer).selected = key;
|
||||
replan = false;
|
||||
Ok(())
|
||||
}
|
||||
Event::AnnotationBrowse(layer, scope, page) => {
|
||||
let address = self.annotation_address_mut(layer);
|
||||
address.scope = scope;
|
||||
address.page = page;
|
||||
replan = false;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(test)]
|
||||
Event::RowExpression(facet, expression) => self.edit_row(&facet, |draft| {
|
||||
draft.editor = text_editor::Content::with_text(&expression);
|
||||
draft.expression = expression;
|
||||
}),
|
||||
Event::RowText(facet, action) => self.edit_row(&facet, |draft| {
|
||||
draft.editor.perform(action);
|
||||
draft.expression = draft.editor.text();
|
||||
}),
|
||||
Event::RowLocal(facet, local) => self.edit_row(&facet, |draft| {
|
||||
draft.local = Some(local);
|
||||
}),
|
||||
};
|
||||
if let Err(error) = result {
|
||||
self.error = Some(error);
|
||||
@@ -431,7 +498,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn editable(&self, project: &Project, facet: &FacetSelector) -> bool {
|
||||
if keyed::supported(facet) {
|
||||
if keyed::supported(facet) || matches!(facet, FacetSelector::Order(_)) {
|
||||
return self
|
||||
.effective_trace(project)
|
||||
.is_some_and(|trace| capture_facet(project, trace.oa, trace.sa, facet).is_ok());
|
||||
@@ -537,6 +604,15 @@ impl State {
|
||||
/// controls. Incomplete inputs retain their stored shape only for controls;
|
||||
/// request construction always requires every selected input to parse.
|
||||
fn combined_value(&self, project: &Project, form_context: bool) -> Result<Value, String> {
|
||||
self.combine(project, form_context, false)
|
||||
}
|
||||
|
||||
fn combine(
|
||||
&self,
|
||||
project: &Project,
|
||||
form_context: bool,
|
||||
skip_orders: bool,
|
||||
) -> Result<Value, String> {
|
||||
let trace = self.effective_trace(project).ok_or("Choose a trace.")?;
|
||||
let (source, target) = if self.direction == TransitionDirection::OaToSa {
|
||||
(trace.oa, trace.sa)
|
||||
@@ -564,15 +640,47 @@ impl State {
|
||||
// overlapping replacement scopes; this order also supports first-equal
|
||||
// discriminator acknowledgment together with explicit descendant values.
|
||||
let mut decisions: Vec<_> = self.decisions.iter().collect();
|
||||
decisions.sort_by_key(|(facet, _)| match facet {
|
||||
FacetSelector::Occurrence(OccurrenceFacet::Constructor) => 0,
|
||||
facet if scalar::grouped(facet) => 1,
|
||||
_ => 2,
|
||||
decisions.sort_by_key(|(facet, _)| {
|
||||
let group = match facet {
|
||||
FacetSelector::Occurrence(OccurrenceFacet::Constructor) => 0,
|
||||
facet if scalar::grouped(facet) => 1,
|
||||
FacetSelector::Order(_) => 3,
|
||||
_ => 2,
|
||||
};
|
||||
(
|
||||
group,
|
||||
keyed_rows::target_selector(facet, self.direction.target_layer()),
|
||||
)
|
||||
});
|
||||
for (facet, decision) in decisions {
|
||||
if *decision == SemanticDecision::KeepTarget {
|
||||
continue;
|
||||
}
|
||||
if let FacetSelector::Order(which) = facet {
|
||||
if !skip_orders {
|
||||
// Invalid order drafts remain visible while dependent controls use the
|
||||
// surviving membership; request construction still rejects them.
|
||||
if let Err(error) =
|
||||
self.project_order(project, &trace, &mut final_value, *which, *decision)
|
||||
&& !form_context
|
||||
{
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if matches!(facet, FacetSelector::Member { collection, .. } if ordered::ordered(*collection).is_some())
|
||||
{
|
||||
self.project_ordered_member(
|
||||
project,
|
||||
&trace,
|
||||
&mut final_value,
|
||||
facet,
|
||||
*decision,
|
||||
form_context,
|
||||
)?;
|
||||
continue;
|
||||
}
|
||||
if keyed::supported(facet) {
|
||||
self.keyed_value(project, &trace, &mut final_value, facet, *decision)?;
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user