Skip to content

Conversation

illume
Copy link
Contributor

@illume illume commented Aug 17, 2025

  • Avoids flashing if the loading is finished before 0.25 seconds.
  • Adds reduced motion support, with a slower animation that includes pauses
  • Avoids SVG animation that mui CircleProgress uses, so it doesn't freeze when main thread is busy on some platforms.
  • Fixes a11y issue to not use progressbar, because we always do not know the progress (and are not updating it), but instead are announcing a status.

How to test

  • Go to storybook, check "Loader" states
  • You could see loaders flash for tenths of a second. Now no loader is seen in these quick loading situations. For example, click on the map, or the plugin catalog after they are loaded for the first time.
  • Loaders would freeze when doing things like installing plugins, waiting for map code to load, waiting for clusters to start, etc. This depends on the platform. Eg, macOS doesn't have this problem (with safari/chrome/electron).
  • a11y behaviour would incorrectly announce a progress bar... but not update the progress.
  • Select OS level reduced motion preference to see the reduced animation

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Aug 17, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: illume

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 17, 2025
@illume illume added kind/bug Categorizes issue or PR as related to a bug. a11y Accessibility related issues minikube and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 17, 2025
@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Aug 17, 2025
This avoids SVG that mui CircleProgress uses, so it doesn't freeze.

Also avoids flashing if the loading is finished before 0.25 seconds.

Fixes a11y issue to not use progressbar, because we always do not
know the progress, but instead are announcing a status.

Removes test which checks that people can add other props to it,
because no one is using this functionality.

Color and size props are used, and are still supported.
@illume illume changed the title fontend: Loader: Fix to not freeze when main thread freezes fontend: Loader: Fix to not freeze when main thread is processing Aug 17, 2025
@illume illume changed the title fontend: Loader: Fix to not freeze when main thread is processing fontend: Loader: Some a11y fixes and platform fix Aug 17, 2025
illume added 2 commits August 18, 2025 09:10
So it looks a bit nicer, and shows more there.

This is similar to how it's done in many places like the storybook
loader for example.
This makes the loader spin a lot slower, with pauses.
/**
* Injects custom loader styles into the document, once for each theme.
*/
function injectLoaderStyle(theme: any) {
Copy link
Contributor

@sniok sniok Aug 18, 2025

Choose a reason for hiding this comment

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

why do styles need to be injected like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What’s your problem with it?

Copy link
Contributor

@sniok sniok Aug 18, 2025

Choose a reason for hiding this comment

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

why not <Box sx={...} /> ?

Copy link
Contributor

Choose a reason for hiding this comment

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

we're using react so we don't have to deal with manually creating dom nodes/styles.
this kind of manual style injection is going to be harder to maintain, prone to bugs, less readable and unnecessary since we have nice abstractions like sx prop. or alternatively you could write a .css file and import it.
I wanted to ask you first, maybe you had some reason to apply styles like this

@joaquimrocha joaquimrocha requested a review from Copilot August 18, 2025 16:00
Copy link

@Copilot 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

This pull request refactors the Loader component to improve accessibility, prevent visual flashing, and fix platform-specific freezing issues. The changes replace MUI's CircularProgress with a custom CSS-based loader implementation.

  • Replaces SVG-based loader with CSS animations to prevent freezing on busy main threads
  • Adds accessibility improvements by changing role from "progressbar" to "status" and including aria-live
  • Implements reduced motion support with slower animations that include pauses
  • Adds a 0.25-second delay to prevent loader flashing for quick operations

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

File Description
frontend/src/components/common/Loader.tsx Complete rewrite implementing custom CSS-based loader with accessibility and reduced motion support
frontend/src/components/common/Loader.test.tsx Updated tests to reflect role changes from "progressbar" to "status" and removed obsolete prop tests
Various snapshot files Updated snapshots showing the new HTML structure with custom CSS classes and improved accessibility attributes

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@@ -15,17 +15,169 @@
*/

import Box from '@mui/material/Box';
import CircularProgress, { CircularProgressProps } from '@mui/material/CircularProgress';
import { alpha, useTheme } from '@mui/material/styles';
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The filename in the title contains a typo: 'fontend' should be 'frontend'.

Copilot uses AI. Check for mistakes.

/**
* Injects custom loader styles into the document, once for each theme.
*/
function injectLoaderStyle(theme: any) {
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The theme parameter should be properly typed instead of using 'any'. Consider using the MUI Theme type or extract the required properties for better type safety.

Suggested change
function injectLoaderStyle(theme: any) {
function injectLoaderStyle(theme: Theme) {

Copilot uses AI. Check for mistakes.

* @returns a color value based on the theme and the provided color prop.
* If no color is provided, it defaults to the primary color of the theme.
*/
function getColor(theme: any, color?: LoaderProps['color']) {
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The theme parameter should be properly typed instead of using 'any'. Consider using the MUI Theme type for better type safety.

Suggested change
function getColor(theme: any, color?: LoaderProps['color']) {
function getColor(theme: Theme, color?: LoaderProps['color']) {

Copilot uses AI. Check for mistakes.

}, [theme]);
const loaderColor = getColor(theme, color);
const muiColorClass = getMuiColorClass(color);
let fadedLoaderColor = React.useMemo(() => withOpacity(loaderColor, 0.1), [loaderColor, theme]);
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The dependency array includes 'theme' but the useMemo callback only uses 'loaderColor'. The theme dependency is unnecessary since loaderColor already captures the theme-dependent value.

Suggested change
let fadedLoaderColor = React.useMemo(() => withOpacity(loaderColor, 0.1), [loaderColor, theme]);
let fadedLoaderColor = React.useMemo(() => withOpacity(loaderColor, 0.1), [loaderColor]);

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
a11y Accessibility related issues approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/bug Categorizes issue or PR as related to a bug. minikube size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants