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 <gzuccare@redhat.com>
This commit is contained in:
parent
bf952c5c7a
commit
5d6c6dc58b
5 changed files with 32 additions and 32 deletions
|
|
@ -16,7 +16,9 @@ export const createBlueprint = async (
|
||||||
await page.getByRole('button', { name: 'Close' }).first().click();
|
await page.getByRole('button', { name: 'Close' }).first().click();
|
||||||
await page.getByRole('button', { name: 'Create blueprint' }).click();
|
await page.getByRole('button', { name: 'Create blueprint' }).click();
|
||||||
await page.getByRole('textbox', { name: 'Search input' }).fill(blueprintName);
|
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) {
|
} catch (error) {
|
||||||
// If the No BP heading was not found, it means the blueprint (possibly) was created -> continue with deletion
|
// If the No BP heading was not found, it means the blueprint (possibly) was created -> continue with deletion
|
||||||
}
|
}
|
||||||
await frame
|
|
||||||
.getByTestId('blueprint-card')
|
// the clickable blueprint cards are a bit awkward, so use the
|
||||||
.getByText(blueprintName)
|
// button's id instead
|
||||||
.click();
|
await frame.locator(`button[id="${blueprintName}"]`).click();
|
||||||
await frame.getByRole('button', { name: 'Menu toggle' }).click();
|
await frame.getByRole('button', { name: 'Menu toggle' }).click();
|
||||||
await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click();
|
await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click();
|
||||||
await frame.getByRole('button', { name: 'Delete' }).click();
|
await frame.getByRole('button', { name: 'Delete' }).click();
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,9 @@ test.describe.serial('test', () => {
|
||||||
await frame
|
await frame
|
||||||
.getByRole('textbox', { name: 'Search input' })
|
.getByRole('textbox', { name: 'Search input' })
|
||||||
.fill(blueprintName);
|
.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: 'Edit blueprint' }).click();
|
||||||
await frame.getByRole('button', { name: 'Additional packages' }).click();
|
await frame.getByRole('button', { name: 'Additional packages' }).click();
|
||||||
|
|
@ -134,7 +136,9 @@ test.describe.serial('test', () => {
|
||||||
await frame
|
await frame
|
||||||
.getByRole('textbox', { name: 'Search input' })
|
.getByRole('textbox', { name: 'Search input' })
|
||||||
.fill(blueprintName);
|
.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();
|
await frame.getByTestId('blueprint-build-image-menu-option').click();
|
||||||
|
|
||||||
// make sure the image is present
|
// make sure the image is present
|
||||||
|
|
@ -154,7 +158,9 @@ test.describe.serial('test', () => {
|
||||||
await frame
|
await frame
|
||||||
.getByRole('textbox', { name: 'Search input' })
|
.getByRole('textbox', { name: 'Search input' })
|
||||||
.fill(blueprintName);
|
.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.getByTestId('blueprint-action-menu-toggle').click();
|
||||||
await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click();
|
await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click();
|
||||||
await frame.getByRole('button', { name: 'Delete' }).click();
|
await frame.getByRole('button', { name: 'Delete' }).click();
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ const BlueprintCard = ({ blueprint }: blueprintProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card
|
||||||
isSelected={blueprint.id === selectedBlueprintId}
|
isClicked={blueprint.id === selectedBlueprintId}
|
||||||
isSelectable
|
|
||||||
data-testid={`blueprint-card`}
|
data-testid={`blueprint-card`}
|
||||||
isCompact
|
isCompact
|
||||||
isClickable
|
isClickable
|
||||||
|
|
@ -43,11 +42,12 @@ const BlueprintCard = ({ blueprint }: blueprintProps) => {
|
||||||
<CardHeader
|
<CardHeader
|
||||||
data-testid={blueprint.id}
|
data-testid={blueprint.id}
|
||||||
selectableActions={{
|
selectableActions={{
|
||||||
name: blueprint.id,
|
name: blueprint.name,
|
||||||
selectableActionId: blueprint.id,
|
// use the name rather than the id. This helps us
|
||||||
selectableActionAriaLabel: blueprint.id,
|
// chose the correct item in the playwright tests
|
||||||
|
selectableActionId: blueprint.name,
|
||||||
|
selectableActionAriaLabel: blueprint.name,
|
||||||
onChange: () => dispatch(setBlueprintId(blueprint.id)),
|
onChange: () => dispatch(setBlueprintId(blueprint.id)),
|
||||||
isHidden: true, // hide the card's checkbox
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardTitle>
|
<CardTitle>
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ type TargetEnvironmentCardProps = {
|
||||||
title: string;
|
title: string;
|
||||||
imageSrc: string;
|
imageSrc: string;
|
||||||
imageAlt: string;
|
imageAlt: string;
|
||||||
isSelected: boolean;
|
isClicked: boolean;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
testId: string;
|
testId: string;
|
||||||
handleOnClick: () => void;
|
handleOnClick: () => void;
|
||||||
|
|
@ -49,7 +49,7 @@ const TargetEnvironmentCard = ({
|
||||||
imageAlt,
|
imageAlt,
|
||||||
handleOnClick,
|
handleOnClick,
|
||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
isSelected,
|
isClicked,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
testId,
|
testId,
|
||||||
}: TargetEnvironmentCardProps) => {
|
}: TargetEnvironmentCardProps) => {
|
||||||
|
|
@ -58,26 +58,18 @@ const TargetEnvironmentCard = ({
|
||||||
data-testid={testId}
|
data-testid={testId}
|
||||||
style={{ textAlign: 'center' } as React.CSSProperties}
|
style={{ textAlign: 'center' } as React.CSSProperties}
|
||||||
onMouseUp={onMouseEnter}
|
onMouseUp={onMouseEnter}
|
||||||
onClick={handleOnClick}
|
isClicked={isClicked}
|
||||||
isSelected={isSelected}
|
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
isSelectable
|
|
||||||
isClickable
|
isClickable
|
||||||
isLarge
|
isLarge
|
||||||
|
onClick={handleOnClick}
|
||||||
>
|
>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
selectableActions={{
|
selectableActions={{
|
||||||
name: title,
|
name: title,
|
||||||
selectableActionId: title.toLowerCase(),
|
selectableActionId: title.toLowerCase(),
|
||||||
selectableActionAriaLabel: title.toLowerCase(),
|
selectableActionAriaLabel: title.toLowerCase(),
|
||||||
// we need to give the `selectableActions` an
|
onClickAction: handleOnClick,
|
||||||
// onChange handler since the card actions use
|
|
||||||
// checkboxes to handle selectable cards.
|
|
||||||
// This workaround reduces noise in the test
|
|
||||||
// output
|
|
||||||
onChange: () => {},
|
|
||||||
isChecked: isSelected,
|
|
||||||
isHidden: true, // hide the card's checkbox
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Flex direction={{ default: 'column' }}>
|
<Flex direction={{ default: 'column' }}>
|
||||||
|
|
@ -165,7 +157,7 @@ const TargetEnvironment = () => {
|
||||||
imageAlt="Amazon Web Services logo"
|
imageAlt="Amazon Web Services logo"
|
||||||
handleOnClick={() => handleToggleEnvironment('aws')}
|
handleOnClick={() => handleToggleEnvironment('aws')}
|
||||||
onMouseEnter={() => prefetchSources({ provider: 'aws' })}
|
onMouseEnter={() => prefetchSources({ provider: 'aws' })}
|
||||||
isSelected={environments.includes('aws')}
|
isClicked={environments.includes('aws')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{supportedEnvironments?.includes('gcp') && (
|
{supportedEnvironments?.includes('gcp') && (
|
||||||
|
|
@ -178,7 +170,7 @@ const TargetEnvironment = () => {
|
||||||
imageAlt="Google Cloud Platform logo"
|
imageAlt="Google Cloud Platform logo"
|
||||||
handleOnClick={() => handleToggleEnvironment('gcp')}
|
handleOnClick={() => handleToggleEnvironment('gcp')}
|
||||||
onMouseEnter={() => prefetchSources({ provider: 'gcp' })}
|
onMouseEnter={() => prefetchSources({ provider: 'gcp' })}
|
||||||
isSelected={environments.includes('gcp')}
|
isClicked={environments.includes('gcp')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{supportedEnvironments?.includes('azure') && (
|
{supportedEnvironments?.includes('azure') && (
|
||||||
|
|
@ -191,7 +183,7 @@ const TargetEnvironment = () => {
|
||||||
imageAlt="Microsoft Azure logo"
|
imageAlt="Microsoft Azure logo"
|
||||||
handleOnClick={() => handleToggleEnvironment('azure')}
|
handleOnClick={() => handleToggleEnvironment('azure')}
|
||||||
onMouseEnter={() => prefetchSources({ provider: 'azure' })}
|
onMouseEnter={() => prefetchSources({ provider: 'azure' })}
|
||||||
isSelected={environments.includes('azure')}
|
isClicked={environments.includes('azure')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{supportedEnvironments?.includes('oci') && (
|
{supportedEnvironments?.includes('oci') && (
|
||||||
|
|
@ -203,7 +195,7 @@ const TargetEnvironment = () => {
|
||||||
}
|
}
|
||||||
imageAlt="Oracle Cloud Infrastructure logo"
|
imageAlt="Oracle Cloud Infrastructure logo"
|
||||||
handleOnClick={() => handleToggleEnvironment('oci')}
|
handleOnClick={() => handleToggleEnvironment('oci')}
|
||||||
isSelected={environments.includes('oci')}
|
isClicked={environments.includes('oci')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Gallery>
|
</Gallery>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ const testTile = async (tile: HTMLElement) => {
|
||||||
|
|
||||||
tile.focus();
|
tile.focus();
|
||||||
await waitFor(() => user.keyboard(' '));
|
await waitFor(() => user.keyboard(' '));
|
||||||
expect(tile).toHaveClass('pf-m-selectable');
|
expect(tile).toHaveClass('pf-m-clickable');
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Create Image Wizard', () => {
|
describe('Create Image Wizard', () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue