Skip to content

chore: Migrate off Decompose/MVIKotlin/Essenty stack - #4929

Draft
malliaridis wants to merge 9 commits into
apache:mainfrom
malliaridis:ui/migrate-off-decompose-mvikotlin
Draft

malliaridis wants to merge 9 commits into
apache:mainfrom
malliaridis:ui/migrate-off-decompose-mvikotlin

Conversation

@malliaridis

@malliaridis malliaridis commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Description

When the new UI module was introduced, we started with the default stack of Decompose, MVIKotlin and Essenty, mainly because other official libraries from JetBrains and Google were not multiplatform-ready or had limited support for web-targets.

Ever since, the ViewModel and official navigation library received significant progress in multiplatform, allowing us to migrate and move away from the mentioned libraries above. This reduces the dependency footprint and third-party libraries and follows more "official" and well-supported patterns and libraries.

Solution

Migrate all existing components to use ViewModels, UseCases and Nav3 and remove related libraries of the previous MVI pattern.

This migration was mainly guided by Claude Code.

Tests

Tests are updated to use the new patterns.

Checklist

Please review the following and check all that apply:

  • I have reviewed the guidelines for How to Contribute and my code conforms to the standards described there to the best of my ability.
  • I have created a Jira issue and added the issue ID to my pull request title.
  • I have given Solr maintainers access to contribute to my PR branch. (optional but recommended, not available for branches on forks living under an organisation)
  • I have developed this patch against the main branch.
  • I have run ./gradlew check.
  • I have added tests for my changes.
  • I have added documentation for the Reference Guide
  • I have added a changelog entry for my change

malliaridis and others added 9 commits September 21, 2026 01:36
DefaultLoggingComponent had no state or behavior, so it no longer needs
the component context or store factory. DefaultMainComponent creates it
without a child context, like the configsets component.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The cluster tab selection moves from a Decompose child slot into a
ClusterViewModel exposing a StateFlow, and ClusterComponent becomes a
factory for it, as in configsets. ClusterContent uses the state-based
NavigationTabs, so the Decompose overload and TabNavigationComponent
are removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The MVIKotlin store, provider and client are replaced with the pattern
used by configsets: an EnvironmentRepository (HTTP), load use cases, an
EnvironmentStateHolder wrapped by an EnvironmentViewModel, and
EnvironmentComponent as a factory. EnvironmentContent gets a stateless
overload that takes the UI state, which the UI test now uses. The store
tests are rewritten against the state holder.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The start store is replaced with a StartRepository (HTTP), a
ConnectUseCase that validates the URL and classifies the outcome, and a
StartStateHolder wrapped by a StartViewModel. Store labels and the
StartComponent.Output callback become a StartEvent flow that StartContent
hands to its parent via onEvent, which the still Decompose-based root
uses for navigation until it is migrated. StartContent gets a stateless
overload used by the previews and the UI test; the integration test now
exercises the state holder with the real use case and repository.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The three auth stores are replaced with the pattern used by configsets:
BasicAuthRepository and OAuthRepository (from the store clients), use
cases for basic authentication, OAuth authorization requests and OAuth
authentication (which also normalize errors), and state holders for
basic auth, OAuth and the shared authentication state. The
AuthenticationViewModel wraps them, and AuthenticationComponent is now
only a factory. The child slots and Output callbacks are gone: the
authentication state holder builds the child state holders from the
supported methods and collects their events into the shared state.

BasicAuthComponent, OAuthComponent and their implementations are
removed, as they only existed as Decompose children. The auth views are
stateless and take state plus callbacks; UserAuthenticationContent hosts
them via slots, hands AuthenticationEvents to its parent and opens the
OAuth authorization URL. The store and component tests are rewritten
against the state holders.

Note: until the root is migrated, view models created by the Decompose
based root live as long as the window and are not scoped to a child.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Decompose child stacks of the root and main components are replaced
with Navigation 3 back stacks held by a RootViewModel and a
MainViewModel, following the routing pattern of the configsets section.
RootComponent and MainComponent are now factories for the components of
their screens, the Start/Authentication/Main outputs became events
handled by the RootViewModel, and MainMenu navigation keeps the
bring-to-front semantics of the previous stack. Transitions are disabled
to keep the previous behavior, and the back handlers never pop the last
entry, as NavDisplay requires a non-empty back stack.

Screens are now created per back stack entry and their view models are
scoped to it, so they are cleared when the entry leaves the back stack.
That also fixes the window-scoped view models noted in the previous
commit.

The desktop and web entry points no longer create a lifecycle, component
context or store factory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
With all components migrated, the remaining glue is removed: the
AppComponentContext and its default implementation, the lifecycle-aware
coroutine scope helpers and the test component context. The
decompose, essenty and mvikotlin dependencies are dropped from the
shared, desktopApp and webApp modules, together with their entries
(including the unused mvikotlin-logging) in the version catalog.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The technology overview no longer describes Decompose, MVIKotlin and
Essenty and introduces the AndroidX ViewModel and Navigation 3
libraries instead. The module structure, component development and
testing pages describe the repository, use case, state holder and view
model layers, the component as a factory, event-based communication with
parents, back stack based navigation and how to test state holders.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Since the UI became an independent sub-project, the :solr:ui paths in
the developer docs no longer resolve. The commands now use `-p ui` with
the :desktopApp and :webApp projects, the web run task is the existing
wasmJsBrowserDevelopmentRun instead of the non-existent
wasmJsBrowserRun (also in the README), the README's desktop command
gets its missing `ui` project directory, and the packaged output path
and module name are corrected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation admin-ui labels Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

admin-ui documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant