diff --git a/__tests__/components/automations/automation-view-toggle.test.tsx b/__tests__/components/automations/automation-view-toggle.test.tsx index 6fcbd5d6..96d103aa 100644 --- a/__tests__/components/automations/automation-view-toggle.test.tsx +++ b/__tests__/components/automations/automation-view-toggle.test.tsx @@ -23,4 +23,24 @@ describe("AutomationViewToggle", () => { expect(onChange).toHaveBeenCalledWith("list"); }); + + it("does not open the menu or fire onChange when disabled", async () => { + // Arrange + const user = userEvent.setup(); + const onChange = vi.fn(); + render( + , + ); + const trigger = screen.getByTestId("automations-view-toggle"); + + // Act — try to open the menu + await user.click(trigger); + + // Assert — menu items never render and onChange stays untouched + expect(trigger).toBeDisabled(); + expect( + screen.queryByTestId("automations-view-toggle-list"), + ).not.toBeInTheDocument(); + expect(onChange).not.toHaveBeenCalled(); + }); }); diff --git a/__tests__/routes/automations-list.test.tsx b/__tests__/routes/automations-list.test.tsx index 47175e9b..ea19ad6a 100644 --- a/__tests__/routes/automations-list.test.tsx +++ b/__tests__/routes/automations-list.test.tsx @@ -166,4 +166,27 @@ describe("AutomationsList — view mode toggle", () => { "list", ); }); + + it("disables the view-mode toggle when the user has no automations", async () => { + // Arrange — service returns an empty list, so the page lands on EmptyState. + vi.mocked(AutomationService.getAutomations).mockResolvedValue({ + automations: [], + total: 0, + }); + const user = userEvent.setup(); + renderList(); + await waitFor(() => { + expect(AutomationService.getAutomations).toHaveBeenCalledTimes(1); + }); + + // Act — try to open the toggle's grid/list menu. + const trigger = await screen.findByTestId("automations-view-toggle"); + await user.click(trigger); + + // Assert — toggle is disabled and clicking it does not reveal the menu. + expect(trigger).toBeDisabled(); + expect( + screen.queryByTestId("automations-view-toggle-list"), + ).not.toBeInTheDocument(); + }); }); diff --git a/src/components/features/automations/automation-view-toggle.tsx b/src/components/features/automations/automation-view-toggle.tsx index 64dba89c..1f37fbb2 100644 --- a/src/components/features/automations/automation-view-toggle.tsx +++ b/src/components/features/automations/automation-view-toggle.tsx @@ -11,6 +11,7 @@ import type { AutomationViewMode } from "./automation-view-mode"; interface AutomationViewToggleProps { view: AutomationViewMode; onChange: (view: AutomationViewMode) => void; + disabled?: boolean; } const VIEW_OPTIONS: { @@ -59,6 +60,7 @@ function ViewMenuItemContent({ export function AutomationViewToggle({ view, onChange, + disabled = false, }: AutomationViewToggleProps) { const { t } = useTranslation("openhands"); const [open, setOpen] = useState(false); @@ -156,9 +158,15 @@ export function AutomationViewToggle({ aria-label={t(I18nKey.AUTOMATIONS$VIEW_MODE)} aria-haspopup="menu" aria-expanded={open} - onClick={() => setOpen((current) => !current)} + aria-disabled={disabled} + disabled={disabled} + onClick={() => { + if (disabled) return; + setOpen((current) => !current); + }} className={cn( "inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-lg border border-[var(--oh-border)] bg-base-secondary text-white transition-colors hover:bg-[var(--oh-interactive-hover)] focus-visible:border-white/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-white/20", + "disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-base-secondary", )} > diff --git a/src/routes/automations-list.tsx b/src/routes/automations-list.tsx index b284cd6f..349cf234 100644 --- a/src/routes/automations-list.tsx +++ b/src/routes/automations-list.tsx @@ -124,6 +124,8 @@ export default function AutomationsList() { }, []); const hasMore = data ? data.total > data.automations.length : false; + const hasNoAutomations = + !isLoading && !isError && data?.automations.length === 0; // Show loading state while checking health if (isHealthLoading) { @@ -193,6 +195,7 @@ export default function AutomationsList() { @@ -208,9 +211,7 @@ export default function AutomationsList() { {isError && !isLoading && } - {!isLoading && !isError && data?.automations.length === 0 && ( - - )} + {hasNoAutomations && } {!isLoading && !isError && data && data.automations.length > 0 && ( <>