Skip to content

Commit

Permalink
[RHOAIENG-5491] Landing page: Info section about AI flows
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 committed Apr 22, 2024
1 parent 0542180 commit 33c8674
Show file tree
Hide file tree
Showing 16 changed files with 578 additions and 30 deletions.
106 changes: 98 additions & 8 deletions frontend/src/__tests__/cypress/cypress/e2e/home/home.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@ import { enabledPage } from '~/__tests__/cypress/cypress/pages/enabled';

type HandlersProps = {
disableHome?: boolean;
disableProjects?: boolean;
disableModelServing?: boolean;
disablePipelines?: boolean;
};

const initIntercepts = ({ disableHome }: HandlersProps) => {
cy.interceptOdh(
'GET /api/config',
mockDashboardConfig({
disableHome,
}),
);
const initIntercepts = (config: HandlersProps = {}) => {
const dashboardConfig = {
disableProjects: false,
disableModelServing: false,
disablePipelines: false,
...config,
};
cy.interceptOdh('GET /api/config', mockDashboardConfig(dashboardConfig));
cy.interceptOdh('GET /api/components', { query: { installed: 'true' } }, mockComponents());
};

describe('Home page', () => {
it('should not be shown by default', () => {
initIntercepts({});
initIntercepts();
cy.visit('/');
cy.findByTestId('enabled-application').should('be.visible');
});
Expand All @@ -30,4 +34,90 @@ describe('Home page', () => {
// enabled applications page is still navigable
enabledPage.visit(true);
});
it('should show the appropriate AI flow cards', () => {
initIntercepts({ disableHome: false });
cy.visit('/');

cy.findByTestId('ai-flow-projects-card').should('be.visible');
cy.findByTestId('ai-flow-train-card').should('be.visible');
cy.findByTestId('ai-flow-models-card').should('be.visible');
});
it('should show the appropriate info cards', () => {
initIntercepts({ disableHome: false });
cy.visit('/');

cy.findByTestId('ai-flow-projects-card').click();
cy.findByTestId('ai-flows-projects-info').should('be.visible');
cy.findByTestId('ai-flows-connections-info').should('be.visible');
cy.findByTestId('ai-flows-storage-info').should('be.visible');

cy.findByTestId('ai-flow-train-card').click();
cy.findByTestId('ai-flows-workbenches-info').should('be.visible');
cy.findByTestId('ai-flows-pipelines-info').should('be.visible');
cy.findByTestId('ai-flows-runs-info').should('be.visible');

cy.findByTestId('ai-flow-models-card').click();
cy.findByTestId('ai-flows-model-servers-info').should('be.visible');
cy.findByTestId('ai-flows-model-deploy-info').should('be.visible');
});
it('should close the info cards on re-click', () => {
initIntercepts({ disableHome: false });
cy.visit('/');

cy.findByTestId('ai-flow-projects-card').click();
cy.findByTestId('ai-flows-projects-info').should('be.visible');
cy.findByTestId('ai-flows-connections-info').should('be.visible');
cy.findByTestId('ai-flows-storage-info').should('be.visible');

cy.findByTestId('ai-flow-projects-card').click();
cy.findByTestId('ai-flows-projects-info').should('not.exist');
cy.findByTestId('ai-flows-connections-info').should('not.exist');
cy.findByTestId('ai-flows-storage-info').should('not.exist');
});
it('should close the info cards on close button click', () => {
initIntercepts({ disableHome: false });
cy.visit('/');

cy.findByTestId('ai-flow-projects-card').click();
cy.findByTestId('ai-flows-projects-info').should('be.visible');
cy.findByTestId('ai-flows-connections-info').should('be.visible');
cy.findByTestId('ai-flows-storage-info').should('be.visible');

cy.findByTestId('ai-flows-close-info').click();
cy.findByTestId('ai-flows-projects-info').should('not.exist');
cy.findByTestId('ai-flows-connections-info').should('not.exist');
cy.findByTestId('ai-flows-storage-info').should('not.exist');
});
it('should hide sections that are disabled', () => {
initIntercepts({
disableHome: false,
disableProjects: true,
});
cy.visit('/');
cy.findByTestId('home-page').should('be.visible');

cy.findByTestId('ai-flow-projects-card').should('not.exist');

initIntercepts({
disableHome: false,
disableModelServing: true,
});
cy.visit('/');
cy.findByTestId('home-page').should('be.visible');
cy.findByTestId('ai-flow-models-card').should('not.exist');
});
it('should hide info cards that are disabled', () => {
initIntercepts({
disableHome: false,
disablePipelines: true,
});
cy.visit('/');
cy.findByTestId('home-page').should('be.visible');

cy.findByTestId('ai-flow-train-card').click();

cy.findByTestId('ai-flows-workbenches-info').should('be.visible');
cy.findByTestId('ai-flows-pipelines-info').should('not.exist');
cy.findByTestId('ai-flows-runs-info').should('not.exist');
});
});
14 changes: 12 additions & 2 deletions frontend/src/concepts/design/DividedGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ type DividedGalleryProps = Omit<GalleryProps, 'minWidths' | 'maxWidths'> & {
minSize: string;
itemCount: number;
showClose?: boolean;
closeAlt?: string;
onClose?: () => void;
closeTestId?: string;
};

import './DividedGallery.scss';
Expand All @@ -16,9 +18,11 @@ const DividedGallery: React.FC<DividedGalleryProps> = ({
minSize,
itemCount,
showClose,
closeAlt,
onClose,
children,
className,
closeTestId,
...rest
}) => (
<div className={css('odh-divided-gallery', className)} {...rest}>
Expand All @@ -30,8 +34,14 @@ const DividedGallery: React.FC<DividedGalleryProps> = ({
{children}
{showClose ? (
<div className="odh-divided-gallery__close">
<Button aria-label="close" isInline variant="plain" onClick={onClose}>
<TimesIcon />
<Button
data-testid={closeTestId}
aria-label={closeAlt || 'close'}
isInline
variant="plain"
onClick={onClose}
>
<TimesIcon alt={`close ${closeAlt}`} />
</Button>
</div>
) : null}
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/concepts/design/InfoGalleryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ButtonVariant,
Flex,
FlexItem,
GalleryItemProps,
Stack,
StackItem,
Text,
Expand All @@ -22,7 +23,7 @@ type InfoGalleryItemProps = {
description: string;
isOpen: boolean;
onClick?: () => void;
};
} & GalleryItemProps;

const InfoGalleryItem: React.FC<InfoGalleryItemProps> = ({
title,
Expand All @@ -31,8 +32,9 @@ const InfoGalleryItem: React.FC<InfoGalleryItemProps> = ({
description,
isOpen,
onClick,
...rest
}) => (
<DividedGalleryItem>
<DividedGalleryItem {...rest}>
<Stack hasGutter>
<StackItem>
<Flex
Expand Down
63 changes: 62 additions & 1 deletion frontend/src/concepts/design/TypeBorderCard.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.odh-type-bordered-card {
position: relative;
border-radius: 16px;
border: var(--pf-v5-global--BorderWidth--sm) solid var(--pf-v5-global--BorderColor--100);
border: 1px solid var(--pf-v5-global--BorderColor--100);
padding: 1px;

&:after {
position: absolute;
width: 48px;
Expand Down Expand Up @@ -77,4 +79,63 @@
background: var(--ai-serving--BorderColor);
}
}
&.m-is-selectable {
&:after {
display: none;
top: unset;
bottom: 0;
transform: rotate( -180deg );
}
&:hover {
cursor: pointer;
}
&:hover, &.m-is-selected {
&:after {
display: block
}
&.project {
border-color: var(--ai-project--BorderColor);
}
&.notebook {
border-color: var(--ai-notebook--BorderColor);
}
&.pipeline {
border-color: var(--ai-pipeline--BorderColor);
}
&.pipeline-run {
border-color: var(--ai-pipeline--BorderColor);
}
&.cluster-storage {
border-color: var(--ai-cluster-storage--BorderColor);
}
&.model-server {
border-color: var(--ai-model-server--BorderColor);
}
&.data-connection {
border-color: var(--ai-data-connection--BorderColor);
}
&.user {
border-color: var(--ai-user--BorderColor);
}
&.group {
border-color: var(--ai-group--BorderColor);
}
&.set-up {
border-color: var(--ai-set-up--BorderColor);
}
&.organize {
border-color: var(--ai-organize--BorderColor);
}
&.training {
border-color: var(--ai-training--BorderColor);
}
&.serving {
border-color: var(--ai-serving--BorderColor);
}
}
&.m-is-selected {
border-width: 2px;
padding: 0;
}
}
}
18 changes: 17 additions & 1 deletion frontend/src/concepts/design/TypeBorderedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,30 @@ import './TypeBorderCard.scss';
type TypeBorderedCardProps = CardProps & {
objectType?: ProjectObjectType;
sectionType?: SectionType;
selectable?: boolean;
selected?: boolean;
};
const TypeBorderedCard: React.FC<TypeBorderedCardProps> = ({
objectType,
sectionType,
className,
selectable,
selected,
...rest
}) => (
<Card className={css(className, 'odh-type-bordered-card', sectionType, objectType)} {...rest} />
<Card
className={css(
className,
'odh-type-bordered-card',
sectionType,
objectType,
selectable && 'm-is-selectable',
selected && 'm-is-selected',
)}
role={selectable ? 'button' : undefined}
aria-expanded={selectable ? selected : undefined}
{...rest}
/>
);

export default TypeBorderedCard;
4 changes: 2 additions & 2 deletions frontend/src/concepts/design/vars.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
:root {
--ai-set-up--BackgroundColor: #ffe8cc;
--ai-organize--BackgroundColor: #fff4cc;
--ai-organize--BackgroundColor: #ffe8cc;
--ai-training--BackgroundColor: #daf2f2;
--ai-serving--BackgroundColor: #e0f0ff;

--ai-set-up--BorderColor: #f8ae54;
--ai-organize--BorderColor: #ffcc17;
--ai-organize--BorderColor: #f8ae54;
--ai-training--BorderColor: #9ad8d8;
--ai-serving--BorderColor: #92c5f9;

Expand Down
4 changes: 4 additions & 0 deletions frontend/src/images/UI_icon-Red_Hat-Branch-Color.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions frontend/src/images/UI_icon-Red_Hat-Chart-Color.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions frontend/src/images/UI_icon-Red_Hat-Folder-Color.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 23 additions & 14 deletions frontend/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,29 @@ import {
PageSectionVariants,
} from '@patternfly/react-core';
import { HomeIcon } from '@patternfly/react-icons';
import { ODH_PRODUCT_NAME } from '~/utilities/const';
import { useAIFlows } from './aiFlows/useAIFlows';

const Home: React.FC = () => (
<PageSection data-testid="home-page" variant={PageSectionVariants.light}>
<Bullseye>
<EmptyState variant="full">
<EmptyStateHeader
titleText="Welcome to the home page"
headingLevel="h4"
icon={<EmptyStateIcon icon={HomeIcon} />}
alt=""
/>
</EmptyState>
</Bullseye>
</PageSection>
);
const Home: React.FC = () => {
const aiFlows = useAIFlows();

if (!aiFlows) {
return (
<PageSection data-testid="home-page-empty" variant={PageSectionVariants.default}>
<Bullseye>
<EmptyState variant="full">
<EmptyStateHeader
titleText={`Welcome to ${ODH_PRODUCT_NAME}`}
headingLevel="h4"
icon={<EmptyStateIcon icon={HomeIcon} />}
/>
</EmptyState>
</Bullseye>
</PageSection>
);
}

return <div data-testid="home-page">{aiFlows}</div>;
};

export default Home;

0 comments on commit 33c8674

Please sign in to comment.