Skip to content

Frontend: upstreamable: Add placeholder buttons to prevent layout shift during project loading - #393

Draft
Tejhan Diallo (tejhan) wants to merge 102 commits into
Azure:headlamp-downstreamfrom
tejhan:project-delete-button-placeholder
Draft

Frontend: upstreamable: Add placeholder buttons to prevent layout shift during project loading#393
Tejhan Diallo (tejhan) wants to merge 102 commits into
Azure:headlamp-downstreamfrom
tejhan:project-delete-button-placeholder

Conversation

@tejhan

Copy link
Copy Markdown
Collaborator

Description

Currently, the project delete button pops in only after async operations resolve (namespace loading, RBAC checks, project type detection), causing a visible layout shift on the project details page.

For custom project types (AKS projects for ex.), there's an additional visual glitch where the default delete button renders first, disappears, then the custom one appears, resulting in a flash/additional layout shift.

These issues typically occur within the first second, but are noticeable at longer load times and are visually inconsistent with most of the statically loaded components on the page.

This PR adds placeholder buttons so the delete button area is standardized from the initial render, which visually aligns with the behavior of most other static components on the project details page.

Note: This PR is related but not exclusive to #392. Additional fixes for the AKSProjectDeleteButton reside there

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring
  • CI/CD changes
  • Other: **___**

Changes Made

  • Added authResolved state that is utilized to shows a placeholder button while namespaces load and RBAC permissions resolve.
  • Changed DeleteButton state to initialize as null when a custom delete button is being resolved.

Testing

  • Unit tests pass
  • Integration tests pass
  • Manual testing completed
  • Performance tested (if applicable)
  • Accessibility tested (if applicable)

Test Cases

Steps to reproduce

  1. Open a standard AKS project
  2. Delete button should be visible on initial page render.
  3. Open a AKS managed project.
  4. Delete button should be visible on initial page render, & shouldn't disappear or flicker afterwards.

Signed-off-by: Joaquim Rocha <joaquim.rocha@microsoft.com>
So it just uses the name.

Signed-off-by: Joaquim Rocha <joaquim.rocha@microsoft.com>
…mand execution

This improves performance by avoiding repeated shell environment
queries and ensures consistent environment variables across commands.

Co-authored-by: Santhosh Nagaraj <sannagaraj@microsoft.com>

Signed-off-by: Joaquim Rocha <joaquim.rocha@microsoft.com>
… execution

This enables AKS Desktop plugin functionality and improves command
execution by using the cached shell environment for better PATH
resolution and consistent environment variables.

Co-authored-by: Santhosh Nagaraj <sannagaraj@microsoft.com>

Signed-off-by: Joaquim Rocha <joaquim.rocha@microsoft.com>
…ugin integration

This extends the frontend to support kubectl commands and integrates
the AKS Desktop plugin with proper permission handling and command
execution capabilities.

Co-authored-by: Santhosh Nagaraj <sannagaraj@microsoft.com>

Signed-off-by: Joaquim Rocha <joaquim.rocha@microsoft.com>
this patch updates the product name which
affects the final binary name

Signed-off-by: yolossn <sannagaraj@microsoft.com>
this patch removes the initialise in the app
start since it was blocking the rendering process
in windows. This is fixed by calling the
getShellEnvironment in runCmd and make sure
getShellEnvironment caches the values instead
of running on each call

Signed-off-by: yolossn <sannagaraj@microsoft.com>
this patch adds consent to aks-desktop specific
commands by default to avoid the user consent
popups

Signed-off-by: yolossn <sannagaraj@microsoft.com>
Signed-off-by: yolossn <sannagaraj@microsoft.com>
…native

So we're more compatible with different platforms.
app: Github OAuth: migrate tests to vitest from jest
app: Revert electron-builder version bump
frontend: Fix frontend tests after rebase
Removes "--format azure" from "az aks get-credentials"
to allow kubeconfig generation compatible with the
custom kubelogin conversion step.

Signed-off-by: yolossn <sannagaraj@microsoft.com>
aksd: Remove azure format from get-credentials
aksd: fix: Respect KUBECONFIG env var when writing to kubeconfig
upstreamable: frontend: Table: Implement keyboard accessible column selector in ColumnVisibilityButton
Copilot AI review requested due to automatic review settings March 10, 2026 11:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes visible layout shifts and button flickering on the project details page that occur while async operations (namespace loading, RBAC checks, custom delete button resolution) resolve. It adds placeholder buttons that maintain the layout area from the initial render, matching the visual behavior of static components on the page.

Changes:

  • Added authResolved state to ProjectDeleteButton to show a placeholder button while RBAC permissions are pending, replacing it seamlessly with the real button once auth resolves.
  • Updated ProjectDetails.tsx to initialize DeleteButton as null when a custom delete button is being resolved, rendering a placeholder ActionButton in its place.
  • Fixed a pre-existing bug where isEnabled returning false never showed the fallback ProjectDeleteButton.

Reviewed changes

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

File Description
frontend/src/components/project/ProjectDeleteButton.tsx Adds namespace-loading and RBAC-pending placeholders to prevent layout shift; introduces authResolved state wired to AuthVisible's onAuthResult/onError callbacks
frontend/src/components/project/ProjectDetails.tsx Initializes DeleteButton as null during async custom-button resolution, renders a placeholder ActionButton; also fixes the isEnabled = false fallback to correctly display ProjectDeleteButton

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/components/project/ProjectDeleteButton.tsx
Comment thread frontend/src/components/project/ProjectDetails.tsx

@illume René Dudfield (illume) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please check the open review comments?

For the commit it could have projects: added.

It's not upstreamable? (I'm not sure... but looks like it could be?) if so please add the upstreamable to the commit/PR title?

@illume
René Dudfield (illume) marked this pull request as draft March 11, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +58 to +88
{!authResolved && (
<ActionButton
description={t('Delete project')}
buttonStyle={buttonStyle}
onClick={() => {}}
icon="mdi:delete"
/>
)}
<AuthVisible
item={projectNamespaces[0]}
authVerb="update"
onAuthResult={() => setAuthResolved(true)}
onError={() => setAuthResolved(true)}
>
{authResolved && (
<>
<ActionButton
description={t('Delete project')}
buttonStyle={buttonStyle}
onClick={() => setOpenDialog(true)}
icon="mdi:delete"
/>
<ProjectDeleteDialog
open={openDialog}
project={project}
onClose={() => setOpenDialog(false)}
namespaces={projectNamespaces}
/>
</>
)}
</AuthVisible>

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

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

With the current authResolved gating, users who are not authorized will briefly see the placeholder button and then it will disappear once onAuthResult fires with allowed: false, causing a layout shift (and a short-lived “Delete” affordance). If the goal is to avoid layout shifts in all cases, consider reserving the space even after auth resolves but is denied (e.g., keep a disabled button with visibility: hidden/aria-hidden, or a fixed-size container) rather than removing it entirely.

Copilot uses AI. Check for mistakes.

@tejhan Tejhan Diallo (tejhan) Mar 12, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The placeholder button exists to prevent layout shift for authorized users (the common case). Making it disabled would cause a visible white -> grey -> white flicker as it transitions to the real button.

For unauthorized users, there would be a brief flash of the placeholder before it disappears, but this comment suggests an empty placeholder for that case - which means these 2 goals are contradictory. Since we check auth first before making the decision of 'showing' it or not, we can't know which placeholder type to use before the auth is done.

Current approach leans toward the most common case so we see zero layout shift.

But this is something that might be a design decision to discuss. (delete button is right aligned)

Comment thread frontend/src/components/project/ProjectDetails.tsx
Comment thread frontend/src/components/project/ProjectDeleteButton.tsx
@tejhan
Tejhan Diallo (tejhan) force-pushed the project-delete-button-placeholder branch from 514c808 to 82dbdc5 Compare March 12, 2026 08:43
@tejhan Tejhan Diallo (tejhan) changed the title Frontend: Add placeholder buttons to prevent layout shift during async loading headlamp: upstreamable: frontend: Add placeholder buttons to prevent layout shift during async loading Mar 12, 2026
@tejhan Tejhan Diallo (tejhan) changed the title headlamp: upstreamable: frontend: Add placeholder buttons to prevent layout shift during async loading Headlamp: upstreamable: frontend: Add placeholder buttons to prevent layout shift during async loading Mar 12, 2026
@tejhan Tejhan Diallo (tejhan) changed the title Headlamp: upstreamable: frontend: Add placeholder buttons to prevent layout shift during async loading Frontend: upstreamable: Add placeholder buttons to prevent layout shift during async loading Mar 12, 2026
@tejhan Tejhan Diallo (tejhan) changed the title Frontend: upstreamable: Add placeholder buttons to prevent layout shift during async loading Frontend: upstreamable: Add placeholder buttons to prevent layout shift during project loading Mar 12, 2026
@illume René Dudfield (illume) added p-none No priority was assigned bug Something isn't working labels Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working p-none No priority was assigned

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants