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

Proposal for Re-Writing the Web UI #2396

Closed
andrewbaldwin44 opened this issue Sep 6, 2023 · 20 comments · Fixed by #2405
Closed

Proposal for Re-Writing the Web UI #2396

andrewbaldwin44 opened this issue Sep 6, 2023 · 20 comments · Fixed by #2405

Comments

@andrewbaldwin44
Copy link
Collaborator

Is your feature request related to a problem? Please describe.

It is time to modernize the Web UI! I find the Web UI to be lacking certain features and flexibility, modernizing the app will allow us to quickly and easily add new features in future tickets.

Describe the solution you'd like

The proposal for this ticket will be to re-write the Web UI using modern web technologies. Upon implementation, the Web UI should have all the same features as the current Web UI, nothing should be removed or added.

Proposal for the new Web UI

I propose a new Web UI using the following technologies:

  • React: a popular JavaScript library, React's component-based architecture allows for reusable UI components, allowing for fast and easy implementation of new features. The strong React community will additionally make it very accessible for developers to contribute to Locust
  • Typescript: TypeScript is a statically-typed superset of JavaScript, enforcing strict Typing in the front-end. With Type-checking on the backend, it is only logical that we have typing on the frontend as well.
  • Tailwind CSS: Tailwind is a utility-first CSS framework that provides numerous benefits over other libraries:
    • Rapid development: Elements can be very quickly styled and prototyped, without having to write custom CSS
    • Enforces consistency: Design consistency is particularly valuable in a project with numerous contributors. Tailwind's utility classes enforce consistency, ensuring a cohesive design throughout the entire project. These utility classes constrain choices related to colors, spacing, typography, and shadows, resulting in a clean and modern interface. This is as opposed to developing using custom CSS or SASS, which quickly results in stylesheets littered with arbitrary values.
    • Customization: Tailwind CSS is highly customizable. You can configure your own utility classes, define custom themes, and extend the default set of classes. This allows for a unique look and feel to the interface, as opposed to a library such as Bootstrap, where the interface is often very uniform
    • Modularity: Tailwind CSS has a modular approach to styling. Each utility class corresponds to a specific CSS property and value, which makes it easy to change or update individual styles without affecting other parts of the application
    • Learning curve: Tailwind has a large community of developers, however for those new to the framework, the learning curve is considerably lower compared to other frameworks. Plus, tools such as IntelliSense in VS Code make it possible to simply auto-complete styles
    • Dark mode 😎
  • Redux: Provides state management throughout the application This allows for data to be accessed as well as updated from anywhere within the application, and the UI will re-render accordingly
  • Redux Toolkit: Redux Toolkit is React Redux "but better". It includes a lot of features that allow for reducing boilerplate that is normally required in Redux applications. It additionally improves consistency and speeds up development
  • React Testing Library: We have a lot of tests on the backend, and some of these tests include testing the HTML response for the Web UI. These tests could be replaced with React Testing Library. We could then expand on these tests in future tickets to cover the entire frontend application
  • Webpack: Webpack will be used to compile the project into static files, allowing for the content to be served from backend. We will use Jinja once again to provide variables between the backend and frontend
  • Echarts: We will use e-charts once again to render the charts

Additional context

Happy to work on this!

@cyberw
Copy link
Collaborator

cyberw commented Sep 6, 2023

Looks good!

My only issue is that it is a lot of frameworks :) (and most of them are new to me...)

Do we really need Redux, or could we get away with just using React.Context?

As for Tailwind vs (for example) Bootstrap, I think having a "standard" look and feel is actually preferable. But if Tailwind is better then that is fine (I really have no idea).

❤️ TypeScript

@cyberw
Copy link
Collaborator

cyberw commented Sep 6, 2023

Is it worth considering a more "pure python" approach like Streamlit?

@andrewbaldwin44
Copy link
Collaborator Author

Yeah I tend to like Redux as I find it can be a bit cleaner when it comes to reading from state and updating, and you can separate the concerns a bit more easily. But of course that is opinionated and for such a small app, I think we can easily get away with using React Context.

My argument against Bootstrap is that you really get locked into their way of doing things, and it offers really little room for any customization. Of course this can be a good thing, but the moment you need to create a component that does not exist within Bootstrap, you end up having to fight with the Framework, or you end up having to write custom CSS. It works well for something like a blog, but anything non-standard can quickly become painful. Other arguments against it would be that it includes a lot of bloatware (things we wouldn't need) and the learning curve is steeper.

If you want a more "bootstrapy" or "standard" look, Tailwind comes with a set of pre-built components, which is much more extensive than Bootstrap, and can all be customized to fit our needs. Or we could even integrate something such as DaisyUI, which I think gives us the best of both worlds (their components lock us into the "standard" look, but we still have the flexibility of utility classes when we need them)

I don't have any experience with Streamlit, but I think you may quickly end up with the same issue: lack of customization, flexibility, and a learning curve. I think you'll have to do a lot of weird things as well to get the app working and looking the way it currently does (the tabbing system would be a set of vertical buttons as tabs don't really exist within Streamlit, overlays don't seem to be easily possible, and I'm not sure how we could get the data in the top right corner to appear in a similar way)

IMO there's no real replacement for JavaScript in the front-end :)

@cyberw
Copy link
Collaborator

cyberw commented Sep 6, 2023

👍 I dont mind using Redux if it is better than React Context, I just want to keep down the number of things I need to learn/understand :)

As for Tailwind vs Bootstrap I really have no idea what is best. We should aim to keep it very simple and very "standard".

I'll try to make some time to try out streamlit. My first impressions are that it seems extremely powerful and easy to use, but I have no idea what limitations there are.

@andrewbaldwin44
Copy link
Collaborator Author

andrewbaldwin44 commented Sep 6, 2023

Since I have something already written with Redux and Tailwind, I can open a PR proposing this as a solution. Then if you find anything too complex I can change it. I think Tailwind is quite simple to understand, it's quite intuitive and not so different from writing CSS. You can see the cheatsheet for example

I think the biggest difficulty you would have with Streamlit is the layout. It doesn't seem so simple to place elements where you want them to be on the page. I think things such as the initial setup form, navbar, and overlays would all have to be custom. This is possible of course, for example Jinja templating could be used once again so that the navbar, forms, and overlays would be controlled by JS / HTML and the tables and charts would be rendered by Streamlit. However to me this seems more effort than it is worth, and then it still wouldn't be a "pure python" approach.

It also might be interesting for you to know that the page for the Streamlit Docs is actually written using Next.js (React) and Tailwind :o

@cyberw
Copy link
Collaborator

cyberw commented Sep 6, 2023

I’d love to see a PR! Once it is completed, we might want to support both old and new versions for a while (if it is possible)

@andrewbaldwin44
Copy link
Collaborator Author

Yup we can easily make this backwards compatible

if modern_ui:
  return render_template("modern_app.html", **self.template_args)

return render_template("index.html", **self.template_args)

@heyman
Copy link
Member

heyman commented Sep 6, 2023

Over the years I've thought quite a bit about how I would structure the Web UI if I were to re-implement it. I would make it a Vue app (with scoped SASS for styling). I've worked on complex apps in Vue where the quality of the codebases have turned out really well, and Vue's model with self contained components that has the HTML template, JS code, and CSS/SASS fits really well with my brain.

Would you consider Vue as an alternative to React + Redux + Redux Toolkit?

I dislike tailwind because I think styling doesn't belong in the HTML and I really like dynamic languages so I'm actually not a huge fan of TypeScript. However, I'm not looking to start a flame war around tech stacks 😅, and I'm very well aware that people opinions around this vary a lot.

I think Webpack is a monstrosity to configure and work with, and I would urge you to consider Rollup and/or Vite instead.

@andrewbaldwin44
Copy link
Collaborator Author

andrewbaldwin44 commented Sep 6, 2023

Personally I would argue that React is the better choice, it has a larger community of developers and I find JSX to be a more natural or flexible approach. Either way, we could sit here all day and argue one over the other. At the end of the day both frameworks have their merits and I think we could make any app equally in one or the other. Personally, I am not very familiar with Vue. If we decide to go in that direction that's of course perfectly fine, unfortunately however I wouldn't be able to help.

I think the argument against Tailwind is rather opinionated, in any project we almost always end up using utility classes anyways, Tailwind simply uses more of them. I think in the context of a React app, it makes a lot of sense and also feels quite natural that we can have all aspects of the UI in one place. And it's not as if we are using inline styles. Either way Tailwind can be used in combination with modular CSS using built-in directives (see @apply). I would still argue this is better than plain modular CSS (or SASS). For an application of this size it does not make sense to engineer our own design system, and we should have a design system in place to enforce consistency and a clean looking UI

I am not really sure what the argument against Typescript is, we already use static typing in the backend, I think it would be logical to follow suite in the frontend

Once again, I am not familiar with Rollup or Vite, I am sure they both have their merits. I can assure you however that the Webpack configuration needed for this is really quite simple

If we can at the very least agree on using React I can submit a PR using the above mentioned frameworks. Then you can see examples of how I implement each and we could discuss more in depth there. I have already written most parts in my own custom Locust implementation, and I think seeing concrete examples can aid in the justification. Let me know if I should go ahead and I can start working on this

@joseiterable
Copy link

joseiterable commented Sep 6, 2023

One thing that I am working on is to create a wrapper API that exposes the necessary Locust functionality for launching load tests and providing endpoints for polling the results. It is slow going given how interconnected the different facets of Locust are.

I think that perhaps focusing efforts on creating such an interface as part of creating a new web ui would allow developers to easily extend said web ui or perhaps create a different one with whatever framework best suits their needs?

@andrewbaldwin44
Copy link
Collaborator Author

@joseiterable How does this differ from the API routes that are already in place? (/swarm to start the tests, /stats/requests to poll the results)

It is already quite simple and documented to extend the Web UI or even create your own Web UI.

My argument here is to choose a framework that would be accessible to everyone, thereby removing the need for users to create their own web ui from scratch. React is the most used framework by a long shot. I think it would be quite well suited to this project, it is easily scalable allowing for us to add new features and improve, and it has the largest community of developers, allowing for anyone to easily contribute

@amard33p
Copy link

amard33p commented Sep 8, 2023

While we are on this topic, may I also suggest few enhancements to the locust HTML report.

  1. Make it easily customisable by adding the ability to pass data to a custom Jinja template. Our usecase is that along with the standard locust HTML report we also capture additional details like per request trace-ids, P95 of workflow times (combination of API calls) etc.
    Currently we perform additional post-processing after load test and build the final report. It would be awesome if we could show all the data in a single self contained HTML file!

  2. Ability to zoom in/out in the graphs (maybe using plotly). For a long running test, the graph becomes compressed and it is difficult to discern anomalies from that.

@cyberw
Copy link
Collaborator

cyberw commented Sep 9, 2023

I dont know what is the best frameworks to choose. With minimal React experience and zero Vue experience, I just dont know what is best. When I read some silly "react vs vue" articles that gave me the impression that Vue is a little more modern and easier to pick up though.

I prefer TypeScript, because typing would make it easier for people to understand and extend/contribute to Locust.

Given that Andrew has shown an interest in actually implementing it using React + Redux + Tailwind + Webpack, I think that has a bit of an advantage (again, to me it sounds like a ton of tooling to do a simple UI, but again, I have no idea, maybe that is just the way to do web UIs in the 2020s :)

@heyman would you be able to put some time into rewriting the UI in Vue?

@andrewbaldwin44
Copy link
Collaborator Author

andrewbaldwin44 commented Sep 11, 2023

I would not say it's accurate to call one framework more modern than the other, both React and Vue are actively maintained, and continuously evolving. The choice between React and Vue (or even Angular) often comes down to familiarity with the framework, and personal preferences. I will concede that Vue may have a more gentle learning curve, but I don't think this compares when we see that the number of developers familiar with React is nearly triple than Vue. To me, when we're looking for something that would make it easy for people to extend/contribute to, React makes more sense.

Although I don't fully understand the motivation, when I have a little bit more time on my hands I can look at re-writing the code into Vue. I don't think it would take me too much time to learn the framework, but I would be nearly writing this from scratch as a lot of features don't translate 1:1 from React to Vue

@cyberw
Copy link
Collaborator

cyberw commented Sep 11, 2023

I didnt mean to say you should rewrite anything, I was just asking if Heyman was ready to put developer time behind his words :)

For me either one is fine. I also have a few friends who do React so that is another advantage...

@KasimAhmic
Copy link
Contributor

I 100% support rewriting the Locust WebUI! Here are some of my thoughts on the subject:

  1. React: I support going with React over the competition. To this day, it's still the most widely used framework and has the highest chance of garnering contributions from others. That said, literally any web framework out there today (React, Angular, Svelte, Solid, Vue, HTMX, etc.) would work just fine for Locust so it doesn't matter too much. Personally, I too am more familiar with React so that would be my pick by default.

  2. TypeScript: 100% supported ❤️

  3. Tailwind CSS: I personally feel like Material UI would be a better pick here as it comes with a myriad of pre-styled components while still being fully customizable. Thoughts?

  4. Redux and Redux Toolkit (RTK): RTK has been immeasurably useful for me at work over the years and I highly recommend it.

    • @cyberw The tl;dr on React Context vs Redux is: Redux is a state management solution whereas Context is more of a state sharing solution. Redux has built in optimizations for preventing needless UI re-renders and RTK allows you to separate your data retrieval/management code from your UI code. Context on the other hand, while convenient, leads to lots of needless re-renders as any component within the Context is subject to re-rendering whether or not it's actually using anything from the Context. It can be a bit more nuanced than this though, this was just a gross oversimplification.
  5. Webpack: I am strongly against the use of Webpack to be honest. While I have no doubt the initial configuration would be simple, I suspect it'll blow up to massive proportions down the line. I would much rather we use Vite for this as it's super easy to get up and running (yarn create vite webui --template react-ts) and it has the added bonus of being ridiculously fast. An example config is below:

    •   import reactSwcPlugin from '@vitejs/plugin-react-swc';
        import { defineConfig } from 'vite';
        import checkerPlugin from 'vite-plugin-checker';
      
        // https://vitejs.dev/config/
        export default defineConfig({
          plugins: [
            // React plugin for Vite
            reactSwcPlugin(),
            // Runs ESLint to verify code quality and TSC to verify types
            checkerPlugin({
              typescript: true,
              eslint: {
                lintCommand: 'eslint --ext .ts,.tsx',
              },
            }),
          ],
        });
  6. React Testing Library: No objections, have had nothing but good experiences with it. In addition to the above comments on Vite, I would prefer we leverage Vitest as a faster alternative to Jest.

  7. E-Charts: No objections.

I have one lingering question though; have we considered how to handle page extensions of the WebUI at all? Today, you can add your own custom pages to Locust using Flask blueprints and templates but if we were to switch to React, that kinda goes out the door, doesn't it? Does anyone know how widely this feature is even used? I know I personally have considered using it in the past but always opted out for one reason or another. If this is a common sentiment, does it make sense to stop supporting the feature?

I'm really excited to see where this goes!

@cyberw
Copy link
Collaborator

cyberw commented Sep 15, 2023

@KasimAhmic everything you said makes sense to me. MaterialUI seems to have a bit bigger following than Tailwind too.

@andrewbaldwin44 , do you think you could do it with Vite and MaterialUI?

@andrewbaldwin44
Copy link
Collaborator Author

@KasimAhmic Glad to hear we can agree on most things!

Yes I do agree we could easily use Vite instead of Webpack, it is true that more and more applications are migrating away from Webpack these days (even Next.js of recent). I only suggested Webpack because that was what I am familiar with but I imagine Vite shouldn't be difficult to learn.

While I do have some of my own reservations with MaterialUI, I do think it could work very well in this project, especially considering how large the userbase is, and considering that a more 'standard' look and feel is preferred.

As for supporting dynamic pages, I did have some ideas as to how it was possible to continue supporting this feature, however if it is possible I would also be in favor of deprecating this feature. I'm not sure if this is a direction we are looking to go in, but I do tend to be more of the opinion that if developers feel there are features missing from the Web UI, then contributing here would be the best course of action.

Let me know what you think, and if we're all agreed I can start the work on this project using React, Typescript, Redux / Redux Toolkit, MaterialUI, and Vite

@cyberw
Copy link
Collaborator

cyberw commented Sep 15, 2023

I agree. I’m sure there are some people (but quite few) using flask blueprints. But we can keep the old UI around for a while. And some type of dynamic pages should be possible in the new solution too, right?

@mquinnfd
Copy link

This has definitely been rolling about my head for a while also - this would be a real killer piece of work to bring Locust's look and feel up to date. I was originally going to suggest just adding a small reactive layer like Reef, but it's awesome to see enthusiasm for a more fleshed out React front end 🥳. I second the vote for Material UI and TypeScript.

I'd be more than happy to contribute to this work 👍


It's maybe a side issue for Slack, but if Flask's UI layer is being removed, would it be worth discussing adoption for FastAPI for the Locust master's web functionality (thus supporting Pydantic for the types in the codebase)?

I'm not sure to what extent people have built on top of Flask routing etc. but as changing the front end will likely be a breaking change anyway, it could be a good time to modernise the master's stack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants