From 5d6c6dc58bac35674482b152a3c9c5a6f2fc098a Mon Sep 17 00:00:00 2001 From: Lucas Garfield Date: Thu, 19 Jun 2025 10:44:21 -0500 Subject: [PATCH] BlueprintCard: Make hand cursor appear on hover This commit fixes an issue where if both isClickable and isSelectable are passed to a card in Patternfly 6, the hand cursor no longer appears on hover and it is not obvious the card is clickable. Co-Author: Gianluca Zuccarelli --- playwright/helpers/wizardHelpers.ts | 12 +++++---- playwright/test.spec.ts | 12 ++++++--- src/Components/Blueprints/BlueprintCard.tsx | 12 ++++----- .../components/TargetEnvironment.tsx | 26 +++++++------------ .../CreateImageWizard.test.tsx | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/playwright/helpers/wizardHelpers.ts b/playwright/helpers/wizardHelpers.ts index 9aa537ca..bef61f68 100644 --- a/playwright/helpers/wizardHelpers.ts +++ b/playwright/helpers/wizardHelpers.ts @@ -16,7 +16,9 @@ export const createBlueprint = async ( await page.getByRole('button', { name: 'Close' }).first().click(); await page.getByRole('button', { name: 'Create blueprint' }).click(); await page.getByRole('textbox', { name: 'Search input' }).fill(blueprintName); - await page.getByTestId('blueprint-card').getByText(blueprintName).click(); + // the clickable blueprint cards are a bit awkward, so use the + // button's id instead + await page.locator(`button[id="${blueprintName}"]`).click(); }; /** @@ -91,10 +93,10 @@ export const deleteBlueprint = async (page: Page, blueprintName: string) => { } catch (error) { // If the No BP heading was not found, it means the blueprint (possibly) was created -> continue with deletion } - await frame - .getByTestId('blueprint-card') - .getByText(blueprintName) - .click(); + + // the clickable blueprint cards are a bit awkward, so use the + // button's id instead + await frame.locator(`button[id="${blueprintName}"]`).click(); await frame.getByRole('button', { name: 'Menu toggle' }).click(); await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click(); await frame.getByRole('button', { name: 'Delete' }).click(); diff --git a/playwright/test.spec.ts b/playwright/test.spec.ts index 3739074a..87d180a3 100644 --- a/playwright/test.spec.ts +++ b/playwright/test.spec.ts @@ -100,7 +100,9 @@ test.describe.serial('test', () => { await frame .getByRole('textbox', { name: 'Search input' }) .fill(blueprintName); - await frame.getByText(blueprintName, { exact: true }).first().click(); + // the clickable blueprint cards are a bit awkward, so use the + // button's id instead + await frame.locator(`button[id="${blueprintName}"]`).click(); await frame.getByRole('button', { name: 'Edit blueprint' }).click(); await frame.getByRole('button', { name: 'Additional packages' }).click(); @@ -134,7 +136,9 @@ test.describe.serial('test', () => { await frame .getByRole('textbox', { name: 'Search input' }) .fill(blueprintName); - await frame.getByText(blueprintName, { exact: true }).first().click(); + // the clickable blueprint cards are a bit awkward, so use the + // button's id instead + await frame.locator(`button[id="${blueprintName}"]`).click(); await frame.getByTestId('blueprint-build-image-menu-option').click(); // make sure the image is present @@ -154,7 +158,9 @@ test.describe.serial('test', () => { await frame .getByRole('textbox', { name: 'Search input' }) .fill(blueprintName); - await frame.getByText(blueprintName, { exact: true }).first().click(); + // the clickable blueprint cards are a bit awkward, so use the + // button's id instead + await frame.locator(`button[id="${blueprintName}"]`).click(); await frame.getByTestId('blueprint-action-menu-toggle').click(); await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click(); await frame.getByRole('button', { name: 'Delete' }).click(); diff --git a/src/Components/Blueprints/BlueprintCard.tsx b/src/Components/Blueprints/BlueprintCard.tsx index cd52d416..d79fc16a 100644 --- a/src/Components/Blueprints/BlueprintCard.tsx +++ b/src/Components/Blueprints/BlueprintCard.tsx @@ -33,8 +33,7 @@ const BlueprintCard = ({ blueprint }: blueprintProps) => { return ( <> { dispatch(setBlueprintId(blueprint.id)), - isHidden: true, // hide the card's checkbox }} > diff --git a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx index cc778cd0..0200c55c 100644 --- a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx +++ b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx @@ -36,7 +36,7 @@ type TargetEnvironmentCardProps = { title: string; imageSrc: string; imageAlt: string; - isSelected: boolean; + isClicked: boolean; isDisabled?: boolean; testId: string; handleOnClick: () => void; @@ -49,7 +49,7 @@ const TargetEnvironmentCard = ({ imageAlt, handleOnClick, onMouseEnter, - isSelected, + isClicked, isDisabled = false, testId, }: TargetEnvironmentCardProps) => { @@ -58,26 +58,18 @@ const TargetEnvironmentCard = ({ data-testid={testId} style={{ textAlign: 'center' } as React.CSSProperties} onMouseUp={onMouseEnter} - onClick={handleOnClick} - isSelected={isSelected} + isClicked={isClicked} isDisabled={isDisabled} - isSelectable isClickable isLarge + onClick={handleOnClick} > {}, - isChecked: isSelected, - isHidden: true, // hide the card's checkbox + onClickAction: handleOnClick, }} > @@ -165,7 +157,7 @@ const TargetEnvironment = () => { imageAlt="Amazon Web Services logo" handleOnClick={() => handleToggleEnvironment('aws')} onMouseEnter={() => prefetchSources({ provider: 'aws' })} - isSelected={environments.includes('aws')} + isClicked={environments.includes('aws')} /> )} {supportedEnvironments?.includes('gcp') && ( @@ -178,7 +170,7 @@ const TargetEnvironment = () => { imageAlt="Google Cloud Platform logo" handleOnClick={() => handleToggleEnvironment('gcp')} onMouseEnter={() => prefetchSources({ provider: 'gcp' })} - isSelected={environments.includes('gcp')} + isClicked={environments.includes('gcp')} /> )} {supportedEnvironments?.includes('azure') && ( @@ -191,7 +183,7 @@ const TargetEnvironment = () => { imageAlt="Microsoft Azure logo" handleOnClick={() => handleToggleEnvironment('azure')} onMouseEnter={() => prefetchSources({ provider: 'azure' })} - isSelected={environments.includes('azure')} + isClicked={environments.includes('azure')} /> )} {supportedEnvironments?.includes('oci') && ( @@ -203,7 +195,7 @@ const TargetEnvironment = () => { } imageAlt="Oracle Cloud Infrastructure logo" handleOnClick={() => handleToggleEnvironment('oci')} - isSelected={environments.includes('oci')} + isClicked={environments.includes('oci')} /> )} diff --git a/src/test/Components/CreateImageWizard/CreateImageWizard.test.tsx b/src/test/Components/CreateImageWizard/CreateImageWizard.test.tsx index 4e63d5c9..bfca971a 100644 --- a/src/test/Components/CreateImageWizard/CreateImageWizard.test.tsx +++ b/src/test/Components/CreateImageWizard/CreateImageWizard.test.tsx @@ -24,7 +24,7 @@ const testTile = async (tile: HTMLElement) => { tile.focus(); await waitFor(() => user.keyboard(' ')); - expect(tile).toHaveClass('pf-m-selectable'); + expect(tile).toHaveClass('pf-m-clickable'); }; describe('Create Image Wizard', () => {