Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widgets for itless environment #716

Merged
merged 5 commits into from
Nov 12, 2024

Conversation

SteveHNH
Copy link
Contributor

Within the itless environment, not all services are available so not all widgets should be available by default for the customers in that environment. This is meant to resolve that using a feature flag that will be checked to ensure that if a customer is in an itless env, they'll get only a subset of the available widgets.

Working on this a bit with @florkbr.

The FR env has a limited set of features when compared to the commercial
environment. Because of this, we should be limiting those within code so
that we only return the useful widgets in itless environments.

This commit adds a WidgetMappingFR type that specifies a subset of the
commercial widgets.

Signed-off-by: Stephen Adams <[email protected]>
If we're running in an ITless environment, we need to use the route that
hands us the FR default widgets instead of the commercial ones. Here
we're using an unleash flag to do that.

Signed-off-by: Stephen Adams <[email protected]>
@Hyperkid123
Copy link
Contributor

@SteveHNH when do you need this? We will soon be using actual CRDs to specify widgets and the widgets should be defined by the available frontends. Just to avoid adding "technical debt" to the repository if we can.

@SteveHNH
Copy link
Contributor Author

@Hyperkid123 oh that sounds great. I didn't know that was on the roadmap. I have tickets for getting widgets in the itless environment so I'm just trying to get those done. The main part of it is that the we need to make sure we only allow widgets that are useful in that environment, so as long as the CRD approach will allow us to do that, I think that should be fine.

Any ETA on that feature?

@Hyperkid123
Copy link
Contributor

ETA is Q4.

But considering there will also be some transition and onboarding from the app side, its like that thing swill be ready in Q1. So I think you should not wait.

@SteveHNH
Copy link
Contributor Author

Okay, that's good to know. I appreciate your willingness to help us get this working in the FR environment, but I'm bummed it adds technical debt. I'll continue working with @florkbr on it and try to make it as clean as possible so it's easy to remove when the time comes.

It turns out we have a feature flag for itless envs already, so we can
leverage it rather than creating a new one.

Signed-off-by: Stephen Adams <[email protected]>
@SteveHNH SteveHNH marked this pull request as ready for review October 31, 2024 14:51
@SteveHNH SteveHNH changed the title [Draft] Widgets for itless environment Widgets for itless environment Oct 31, 2024
@Hyperkid123
Copy link
Contributor

Oh, this was a technical debt from the start. We knew we would replace it eventually. But the changes we are working are not trivial. Don't worry about it.

@@ -280,6 +281,15 @@ func GetWidgetMappings(w http.ResponseWriter, r *http.Request) {
handleDashboardResponse[models.WidgetModuleFederationMapping](resp, err, w)
}

func GetWidgetMappingsFR(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@SteveHNH I wanted to list out a few long term considerations we will need in the future (I know you and I have discussed several of these offline).

  1. We currently only support one template type (currently "landingPage"). See: https://github.com/RedHatInsights/chrome-service-backend/blob/main/docs/dashboard-layouts.md#base-layouts (backend) and https://github.com/RedHatInsights/widget-layout/blob/master/src/api/dashboard-templates.ts#L13 (frontend).
  2. We plan to migrate this backend logic to its own service (outside of chrome service) and allow for additional "types" in the future. For example if another UI - such as the insights UI - would want to utilize our common widgetized layout service but render a different template and widgets than our landing page.
  3. As @Hyperkid123 pointed out - we also will be migrating the individual widget configurations into the applications that surface them (via frontend config and the frontend operator).
  4. Finally - we need to consider the ordering of widgets by default (when a user first loads the template type and it is automatically forked). I do not believe it is a requirement today - but would we ever want to have a different base layout for the landing page in itless than we do in commercial?

Getting back to this PR though - we have a few options to unblock us in the short term:

  1. Fork the widget-mapping itself for itless (this PR). This would pose minimal risk to our commercial flow - however will have duplication between commercial and itless widget-mappings (for those widgets that appear in both lists). We would also need to remember to add any new widgets that itless would be interested in to both lists.
  2. Add a new metadata/config field inside of each widget struct to indicate if it should appear in the itless environment (more self-service model). This would prevent the duplicated widget-mapping (as we would just filter for that metadata field when running inside of itless). However this model doesn't scale well when it comes to adding support for multiple envs, layouts, etc. and could result in widgets appearing in itless unexpectedly if the field is copy/pasted. This also defeats the purpose of having the widget-mapping (whitelist of widgets that can be rendered).

That being said - I think I prefer option 1 (as you have here). My only concern is we are not updating the base layout for itless as well. See https://github.com/RedHatInsights/chrome-service-backend/blob/main/rest/service/dashboardTemplate.go#L450-L507. This means each time the "landingPage" layout if forked when the user first loads the page in itless - we will have references in the template to widgets that do not exist in the itless widget mapping (such as "ansible"). I believe these widgets will simply be ignored by the UI as they do not appear in the mapping - however we should confirm that in our itless environment and confirm customizing the layout works as expected (even with these invalid references).

Copy link
Contributor

@Hyperkid123 Hyperkid123 Nov 5, 2024

Choose a reason for hiding this comment

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

@florkbr I'd like to provide a 3rd option. Which is using feature flags to enable/disable items in an environment. rather than adding a flag saying this is for itless. Why?

Well, we want feature flags anyway, it will be easier to maintain without introducing tech debt, and it will have the same effect of "messed up initial layout" anyway.

Chrome service is hooked up to unleash already. We can do some "inverted" feature flags like "widget.supportCase.hidden". This way we can remove the widget from a layout when it gets "forked" or when the struct is created from the base layout yaml

Copy link
Contributor

Choose a reason for hiding this comment

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

@Hyperkid123 that seems like a reasonable approach to me - I think I was deep in the itless headspace with the other 2 options - I like that solution more. @SteveHNH thoughts on using @Hyperkid123's suggestion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good to me! I understand the idea, but I don't fully understand how to make that happen. This is also the first time I've messed with this code, so I just need to dive in and get a handle on it. Thanks for the feedback!

- Added a string to each widget to identify its corresponding
  featureflag
- If the 'chrome-service.filterWidgets.enable' flag is set, then a
  function filters through the widgets to see which ones are meant to be
  hidden. By using this flag, we prevent searching for disabled widgets
  when we don't need to. It will simply load the defaults.

Signed-off-by: Stephen Adams <[email protected]>
@SteveHNH
Copy link
Contributor Author

SteveHNH commented Nov 8, 2024

I reworked the widget filtering. The only thing that bothers me is the looping through widgets to see which ones to turn on/off. There might be a smarter way to go after this. I feel like this could introduce a little lag by needing to reach out to unleash for each one.

The other downside I can see is that if for some reason Unleash is unavailable when a user hits the service, the chrome-service.filterWidgets.enable flag could get set to false which would throw all the default widgets at them by default. According to Bryan, this would load some stuff into the DB that we don't want and make it difficult to reset things. But that was going to be a problem anyway, even with the first attempt I made at setting this up.

I'm open to ideas on how we might resolve that if there are any. Maybe invert that filterWidgets check? The worst case would be a commercial customer would see a limited set of widgets until Unleash came back.

Copy link
Contributor

@Hyperkid123 Hyperkid123 left a comment

Choose a reason for hiding this comment

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

Just a small nit, but I think we are good with this.

filteredWidgets := make(map[models.AvailableWidgets]models.ModuleFederationMetadata)

for key, value := range widgetMapping {
if !featureflags.IsEnabled(value.FeatureFlag) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Care to add a comment here, please? Because this is inverted it might be a headscratcher for us when we look at the code in a couple fo weeks. I had to read it twice already 😆

This change modifies the logic for widgets so that instead of creating a
new mapping and returning it, we just delete the widget from the
original map. This makes it so that we're not using inverse logic and
creating confusion where we don't need it.

Signed-off-by: Stephen Adams <[email protected]>
@SteveHNH
Copy link
Contributor Author

@Hyperkid123 I went ahead and figured out how to un-invert that logic so that it reads a little more clearly. Added a comment as well.

@Hyperkid123
Copy link
Contributor

/retest

@Hyperkid123 Hyperkid123 merged commit f806bc4 into RedHatInsights:main Nov 12, 2024
6 of 8 checks passed
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.

3 participants