Lately I have noticed of a couple of seemingly unrelated issues with our UI infrastructure. It got me thinking about ways to fix those issues, and specifically about the lack of a broader direction for our UI.
I would like to present a vision doc that will describe how I see the Foreman UI in the future and what action we can take to get us there. One of my guiding principles for this doc is that I do understand that we we are all busy people and we don’t have the time to put a lot of effort in pure technical debt items without a clear benefit to our users. I want to show an evolutionary approach to the UI modernization effort, where we take one small step at a time to get our UI up to a higher standard. I would like to avoid a revolution approach where we change the UI drastically in a disruptive way.
I will start with the issues and requests I have identified already and then I will suggest a vision and a set of steps to get there.
Old infrastructure:
- We are using Enzyme snapshot tests. This framework does not support React 18 at all with limited workaround for React 17: Resurrection of the client-side infrastructure upgrade effort - #3 by Ron_Lavi . We already started the process of converting those snapshots to proper RTL with guidelines outlined in foreman/developer_docs/ui-testing-guidelines.asciidoc at 15f80b47f592943357cfb5dcdbe62620b978bfae · theforeman/foreman · GitHub .
- React 16 active support ended 5 years ago. While we still receive security updates, newer versions of components can drop support for older react versions. This may become a problem once we want to upgrade one of our dependencies. For example PatternFly supports only two most recent versions of React (Meaning PF6 supports React 17 and 18): PatternFly • Develop with PatternFly
Multiple UI component technology stacks:
Currently our UI uses a lot of different UI technology stacks in different parts of the application. Currently we use ERB, jquery, angular (in Katello), PatternFly 3, PatternFly 5 and redux simultaneously. This creates a steeper learning curve for developers, complicates addition of new features and creates a non-unified visual experience.
UI testing infrastructure:
Current testing that involves UI elements is not standardized and has a lot of workarounds spread around the code. This makes the code unstable and difficult to read and modify. We are using Capybara for “integration” tests, and there is also the Robottelo project that is used for downstream testing. Both are suffering from instability and the amount of asynchronous UI processes that are part of the UI flow.
Future proofing:
While not strictly an existing problem, I think we should also mention two requirements here.
- We want to lower the bar for creation of alternative UI projects, especially now with the whole AI and vibe coding trend.
- We want to make sure it is easier to modernize our current UI stack. In easier, I mean laying the ground for better tests, so changes in the UI will require less rewrite also to our testing framework.
The vision:
- Clearly defined JSON interface for communicating with the UI.
- The UI may be deployed separately in a dedicated container.
- Our UI should use the MVVM pattern in React, along the lines of what is described in MVVM Architecture in React: A Beginner’s Guide with Examples | by Frontend Highlights | Medium
- The UI will be based on React and a single version of PattrnFly
We will be able to test the Foreman functionality by calling this JSON interface, instead of emulating UI interactions.
The UI deployment will become simpler, since we will have only one place to serve the whole our UI, as opposed to the current state, where we have static objects, webpack-compiled objects and dynamic HTML pages.
The MVVM pattern seem like a good fit for our UI, since it is about highly-interactive and interconnected components.
In case we will want to perform test that involve UI, we will be able to build an abstraction layer above the PatternFly components to make the access to our UI elements more streamlined and less prone to errors and reinventing the wheel. In my opinion, we will also be able to create more robust tests for both the business logic and the UI if we also integrate the idea of testable snapshots as described here: Enhancing our tests with stable snapshots for UI testing .
The way to get there:
First I will describe the desired end state. We want to have a page built on top of latest PatternFly components. This page will use state and custom hooks to manage the API requests/responses (the view model). For the model we can either create dedicated objects or use the API responses directly (similar to our current state in redux). The model will be retrieved by a dedicated endpoint on the server side that can be different from the one used by the “official” API.
I think we should not use the same endpoint for the “official” API and for the API calls performed by the UI. The UI is stateful, and does not face the user directly. This will enable us to differentiate our login and security mechanisms for example. We also should make sure we have an autogenerated description for the API, so discovery services will be able to “learn” our available endpoints.
Given that this is the end state, the way to get there is different for each component and it’s complexities.
I think we should consider this doc as a guideline for future UI refactorings and make sure we follow it.
I would like to hear opinions about this strategy and see if I missed some nuances in this approach that would prevent this from happening.