Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit 22145e8

Browse files
matejvasekclaude
andcommitted
fix: use PF Button isLoading for refresh spinner
The custom CSS spin animation on SyncAltIcon was not the standard PatternFly approach. Replace it with the built-in Button isLoading prop, which shows a native PF spinner and handles prefers-reduced-motion automatically. Also place the create and refresh buttons side-by-side with a toolbar separator instead of right-aligning refresh, and disable the refresh button while a fetch is in flight. Signed-off-by: Matej Vašek <matejvasek@gmail.com> Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d2ea352 commit 22145e8

3 files changed

Lines changed: 24 additions & 31 deletions

File tree

src/views/FunctionsListPage.css

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/views/FunctionsListPage.test.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ describe('FunctionsListPage', () => {
462462
});
463463
});
464464

465-
it('does not spin the refresh icon on initial page load', async () => {
465+
it('does not show spinner on refresh button during initial page load', async () => {
466466
renderAuthenticated();
467467
mockUseSourceControl.mockReturnValue({
468468
listFunctionRepos: vi.fn().mockResolvedValue([repoFixture('fn-a')]),
@@ -478,11 +478,11 @@ describe('FunctionsListPage', () => {
478478

479479
await screen.findByTestId('fn-name');
480480

481-
const icon = screen.getByRole('button', { name: 'Refresh' }).querySelector('svg');
482-
expect(icon?.classList.contains('func-console__refresh-spin')).toBe(false);
481+
const refreshBtn = screen.getByRole('button', { name: 'Refresh' });
482+
expect(refreshBtn.querySelector('[role="progressbar"]')).not.toBeInTheDocument();
483483
});
484484

485-
it('spins the refresh icon only while a button-triggered refresh is in flight', async () => {
485+
it('shows spinner on refresh button only while a button-triggered refresh is in flight', async () => {
486486
renderAuthenticated();
487487
let resolveRepos: (value: unknown[]) => void;
488488
const mockListRepos = vi.fn().mockImplementation(
@@ -507,16 +507,16 @@ describe('FunctionsListPage', () => {
507507
resolveRepos!([repoFixture('fn-a')]);
508508
await screen.findByTestId('fn-name');
509509

510-
const icon = screen.getByRole('button', { name: 'Refresh' }).querySelector('svg');
510+
const refreshBtn = screen.getByRole('button', { name: 'Refresh' });
511511

512-
// Click refresh -- icon should spin
513-
await userEvent.click(screen.getByRole('button', { name: 'Refresh' }));
514-
expect(icon?.classList.contains('func-console__refresh-spin')).toBe(true);
512+
// Click refresh -- should show spinner
513+
await userEvent.click(refreshBtn);
514+
expect(refreshBtn.querySelector('[role="progressbar"]')).toBeInTheDocument();
515515

516-
// Resolve the refresh fetch -- icon should stop
516+
// Resolve the refresh fetch -- spinner should disappear
517517
resolveRepos!([repoFixture('fn-a')]);
518518
await waitFor(() => {
519-
expect(icon?.classList.contains('func-console__refresh-spin')).toBe(false);
519+
expect(refreshBtn.querySelector('[role="progressbar"]')).not.toBeInTheDocument();
520520
});
521521
});
522522

src/views/FunctionsListPage.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
Spinner,
1313
Toolbar,
1414
ToolbarContent,
15-
ToolbarGroup,
1615
ToolbarItem,
1716
Tooltip,
1817
} from '@patternfly/react-core';
@@ -31,7 +30,6 @@ import { useClusterService } from '../services/cluster/useClusterService';
3130
import { useSourceControlService } from '../services/source-control/useSourceControlService';
3231
import { RepoMetadata } from '../services/types';
3332
import { errorMessage, parseNamespaceAndRuntime } from '../utils/utils';
34-
import './FunctionsListPage.css';
3533

3634
export default function FunctionsListPage() {
3735
return (
@@ -87,17 +85,20 @@ function FunctionsListPageContent() {
8785
</Button>
8886
)}
8987
</ToolbarItem>
90-
<ToolbarGroup align={{ default: 'alignEnd' }}>
91-
<ToolbarItem>
92-
<Tooltip content={t('Refresh')}>
93-
<Button variant="plain" aria-label={t('Refresh')} onClick={onRefresh}>
94-
<SyncAltIcon
95-
className={refreshing ? 'func-console__refresh-spin' : undefined}
96-
/>
97-
</Button>
98-
</Tooltip>
99-
</ToolbarItem>
100-
</ToolbarGroup>
88+
<ToolbarItem variant="separator" />
89+
<ToolbarItem>
90+
<Tooltip content={t('Refresh')}>
91+
<Button
92+
variant="plain"
93+
aria-label={t('Refresh')}
94+
onClick={onRefresh}
95+
isLoading={refreshing}
96+
spinnerAriaLabel={t('Refreshing')}
97+
isDisabled={refreshing}
98+
icon={<SyncAltIcon />}
99+
/>
100+
</Tooltip>
101+
</ToolbarItem>
101102
</ToolbarContent>
102103
</Toolbar>
103104
<FunctionTable functions={functions} onEdit={onEdit} />

0 commit comments

Comments
 (0)