Skip to content

Commit

Permalink
app: add zero state to image builder
Browse files Browse the repository at this point in the history
This commit introduces the zero state to the image builder application.
When the user doesn't have any composes in the image-builder data base,
they are navigated to a welcome page.

This welcome page exposes a button to create an image.
When the user gets to click on the button, the wizard opens up in a
modal and the user can create their first image.

Once the creation is under going, the user is navigated back to the
images table where they can track progress of the image being built up.
  • Loading branch information
adonispuente authored and lavocatt committed Sep 20, 2023
1 parent 1bb7519 commit ad8ad71
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { Suspense, useEffect, useState } from 'react';

import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
import NotificationsPortal from '@redhat-cloud-services/frontend-components-notifications/NotificationPortal';
Expand Down
4 changes: 4 additions & 0 deletions src/Components/CreateImageWizard/CreateImageWizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import componentTypes from '@data-driven-forms/react-form-renderer/component-types';
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import { useFlag } from '@unleash/proxy-client-react';
import PropTypes from 'prop-types';
import { useDispatch, useStore } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';

Expand Down Expand Up @@ -666,4 +667,7 @@ const CreateImageWizard = () => {
);
};

ImageCreator.propTypes = {
setSelected: PropTypes.any,
};
export default CreateImageWizard;
9 changes: 9 additions & 0 deletions src/Components/ImagesTable/ImagesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import { Link, NavigateFunction, useNavigate } from 'react-router-dom';

import './ImagesTable.scss';

import {
AwsDetails,
AwsS3Details,
Expand All @@ -45,6 +46,7 @@ import {
AWS_S3_EXPIRATION_TIME_IN_HOURS,
STATUS_POLLING_INTERVAL,
} from '../../constants';
import { ZERO_IMAGES } from '../../constants';
import {
ComposesResponseItem,
ComposeStatus,
Expand All @@ -58,6 +60,7 @@ import {
} from '../../Utilities/time';

const ImagesTable = () => {
const navigate = useNavigate();
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(10);

Expand All @@ -80,6 +83,12 @@ const ImagesTable = () => {
const composes = data.data;
const itemCount = data.meta.count;

// If the user has yet no images in their account, send them to the zero state
// url where they'll have help to get started.
if (composes.length <= ZERO_IMAGES) {
navigate(resolveRelPath('zerostate'));
}

return (
<>
{data.meta.count === 0 && <EmptyImagesTable />}
Expand Down
76 changes: 75 additions & 1 deletion src/Router.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,82 @@
import React, { lazy, Suspense } from 'react';
import React, { Suspense, lazy, useState } from 'react';

import { Button } from '@patternfly/react-core';
import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent';
import ErrorState from '@redhat-cloud-services/frontend-components/ErrorState';
import { useFlag } from '@unleash/proxy-client-react';
import { Route, Routes } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import EdgeImageDetail from './Components/edge/ImageDetails';
import ShareImageModal from './Components/ShareImageModal/ShareImageModal';
import { ZERO_IMAGES } from './constants';
import { useGetComposesQuery } from './store/imageBuilderApi';
import { manageEdgeImagesUrlName } from './Utilities/edge';
import { resolveRelPath } from './Utilities/path';

const LandingPage = lazy(() => import('./Components/LandingPage/LandingPage'));
const CreateImageWizard = lazy(() =>
import('./Components/CreateImageWizard/CreateImageWizard')
);

/**
* Help page for newcomers creating their first image if they've never did it.
* Is considered a newcomer a user who has ZERO_IMAGES composes in their
* account. The user gets the possibility to click on a `create image` button
* that will open the wizard for them.
*
* When the user gets an image (at any point in time during which this component
* is displayed on screen) they will get navigated back to the LandingPage.
*
* caveat:
* This component takes care of displaying itself the CreateImageWizard. Meaning
* that the wizard is not being displayed using the navigation system. This is
* valid for-now™ [2023-09] because the wizard is being displayed in a modal.
* This would most likely have to get updated when the wizard will get changed
* to an InPage mode.
*/
export const AppZeroState = () => {
const [wizardOpenned, setWizardOpenned] = useState(false);
const navigate = useNavigate();

const { data, isSuccess } = useGetComposesQuery({
limit: 10,
});
if (!isSuccess) {
return undefined;
}

const composes = data.data;

if (composes.length > ZERO_IMAGES) {
navigate(resolveRelPath(''));
}

return (
<AsyncComponent
appName="dashboard"
module="./AppZeroState"
scope="dashboard"
ErrorComponent={<ErrorState />}
app="Images"
appId="images_zero_state"
customText="Create your image by using the Image Builder wizard."
customButton={
<>
{wizardOpenned && <CreateImageWizard />}
<Button
className="pf-c-button pf-m-primary pf-u-p-md pf-u-font-size-md"
data-testid="create-image-action"
onClick={() => setWizardOpenned(true)}
>
Create image
</Button>
</>
}
/>
);
};

export const Router = () => {
const edgeParityFlag = useFlag('edgeParity.image-list');
return (
Expand All @@ -35,6 +100,15 @@ export const Router = () => {
<Route path="share/:composeId" element={<ShareImageModal />} />
</Route>

<Route
path="zerostate"
element={
<Suspense>
<AppZeroState />
</Suspense>
}
/>

{edgeParityFlag && (
<Route
path={`/${manageEdgeImagesUrlName}/:imageId`}
Expand Down
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const UNIT_KIB = 1024 ** 1;
export const UNIT_MIB = 1024 ** 2;
export const UNIT_GIB = 1024 ** 3;

export const ZERO_IMAGES = 0;

export const RELEASES = new Map([
[RHEL_9, 'Red Hat Enterprise Linux (RHEL) 9'],
[RHEL_8, 'Red Hat Enterprise Linux (RHEL) 8'],
Expand Down

0 comments on commit ad8ad71

Please sign in to comment.