Skip to content

Conversation

@pragmatrix
Copy link
Owner

I suspect that the complexities of typed hierarchies is too much for me and there must be a simpler way. In this PR I took some inspiration from event sourcing to experiment with a systems / aggregate approach that - in the end - may result in a fully incremental system that is overall simpler to understand, easier to maintain, and supports adding cross-cutting features without to much accidental complexity.

@pragmatrix pragmatrix changed the title First rudimentary implementation of the DesktopSystem Experiment: First rudimentary implementation of the DesktopSystem Feb 6, 2026
@pragmatrix pragmatrix changed the title Experiment: First rudimentary implementation of the DesktopSystem Experiment: Event Sourcing Feb 6, 2026
@pragmatrix pragmatrix requested a review from Copilot February 12, 2026 07:18
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces an event-sourced “system/aggregate” approach for the desktop UI, refactoring intent handling into command transactions and aggregating layout/state updates centrally.

Changes:

  • Added DesktopSystem + supporting Cmd/Transaction primitives to apply commands and update UI effects.
  • Refactored desktop/project/launcher interaction flow to return commands instead of UserIntent.
  • Updated massive_layout API (padding and child/nesting naming) and broadened re-exports in a couple of modules.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
shell/src/application_context.rs Small formatting-only change around animation cycle upgrade call.
layout/src/lib.rs Switches to wildcard re-exports for layout public API.
layout/src/layouter.rs Renames childrennested, updates builder API (padding), adds Thickness conversions, updates tests accordingly.
layout/src/dimensional_types.rs Adds Thickness conversion from (Padding, Padding) and imports Padding from crate.
desktop/src/projects/project_presenter.rs Introduces ProjectCommand; shifts presenter transitions to return Cmd and updates layout construction calls.
desktop/src/projects/project.rs Splits LaunchGroup into properties + contents; introduces LaunchGroupProperties.
desktop/src/projects/mod.rs Switches to wildcard re-exports for the projects module API.
desktop/src/projects/launcher_presenter.rs Returns Cmd, emits DesktopCommand on launcher interactions, returns insertion index on present.
desktop/src/lib.rs Adds new modules (aggregates, desktop_system, event_sourcing) and re-exports aggregates.
desktop/src/event_sourcing/mod.rs Adds Cmd and Transaction primitives and composition ops for event-sourcing style updates.
desktop/src/desktop_system.rs New DesktopSystem aggregate applying commands, managing hierarchy/layout specs, and updating effects.
desktop/src/desktop_presenter.rs Refactors event forwarding to return Cmd; exposes apply_layout; adjusts layout building for nested.
desktop/src/desktop_interaction.rs Replaces UserIntent with Cmd/DesktopCommand and updates keyboard preprocessing.
desktop/src/desktop.rs Replaces presenter/interaction wiring with DesktopSystem and routes commands via transact + update_effects.
desktop/src/band_presenter.rs Removes special-case “present primary instance”; returns insertion index; updates layout to use nested.
desktop/src/aggregates/ordered_hierarchy.rs New ordered hierarchy aggregate with add/insert/remove and unit tests.
desktop/src/aggregates/mod.rs New aggregates module exports.
desktop/src/aggregates/layout_specs.rs New small Map wrapper with typed erroring remove and indexing.
.github/copilot-instructions.md Adds guidance to prefer failing on unexpected states over silent defensive handling.


use derive_more::{From, Index, IndexMut, Into};

use crate::Padding;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a dependency from dimensional_types back to Padding (which appears to live in the layouter side), increasing module coupling in a place that otherwise looks like a low-level geometry/types module. Consider moving this From<(Padding, Padding)> for Thickness impl into layouter.rs (or colocating Padding with the other dimensional types) to keep dimensional_types independent of higher-level layout concerns.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +49
impl<const RANK: usize> From<(Padding<RANK>, Padding<RANK>)> for Thickness<RANK> {
fn from((leading, trailing): (Padding<RANK>, Padding<RANK>)) -> Self {
Self {
leading: leading.into(),
trailing: trailing.into(),
}
}
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a dependency from dimensional_types back to Padding (which appears to live in the layouter side), increasing module coupling in a place that otherwise looks like a low-level geometry/types module. Consider moving this From<(Padding, Padding)> for Thickness impl into layouter.rs (or colocating Padding with the other dimensional types) to keep dimensional_types independent of higher-level layout concerns.

Copilot uses AI. Check for mistakes.
Comment on lines 299 to 308
ProjectCommand::AddLauncher {
group,
id,
profile: _,
} => {
let target = DesktopTarget::Launcher(id);
self.hierarchy.add(group.into(), target.clone())?;
self.layout_specs
.insert_or_update(target, self.default_panel_size);
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The profile payload in ProjectCommand::AddLauncher is currently ignored (profile: _). That makes the command misleading as an event-sourcing primitive (it appears to carry the data required to apply the change, but the system drops it). Either remove profile from the command if it’s intentionally unused by the system state, or store/apply it (e.g., update the corresponding presenter/project aggregate) so replaying commands reconstructs all necessary state.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +42
#[allow(non_upper_case_globals)]
pub const None: Self = Self(Vec::new());
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a non-UPPERCASE associated constant requires suppressing non_upper_case_globals, which is a sign the API is fighting Rust naming conventions. Consider replacing this with a conventional pub const NONE: Self = ... or a pub fn none() -> Self constructor to avoid the lint suppression while keeping call sites readable.

Suggested change
#[allow(non_upper_case_globals)]
pub const None: Self = Self(Vec::new());
pub const NONE: Self = Self(Vec::new());

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant