From ed10581191b9051bc3e64bcc9576f4d860cd2548 Mon Sep 17 00:00:00 2001
From: Alejandro Visiedo
Date: Sun, 1 Oct 2023 16:46:17 +0200
Subject: [PATCH] HMS-2667 fix: align wizard page 1
Align the preparation wizard page with what is defined in the mock-ups.
Signed-off-by: Alejandro Visiedo
---
src/AppContext.tsx | 42 +++-
src/AppEntry.tsx | 31 ++-
.../PagePreparation/PagePreparation.scss | 8 -
.../PagePreparation/PagePreparation.tsx | 194 ++++++++++--------
src/Routes/WizardPage/WizardPage.tsx | 115 ++++++++---
5 files changed, 268 insertions(+), 122 deletions(-)
diff --git a/src/AppContext.tsx b/src/AppContext.tsx
index ed5c41b..0d0a559 100644
--- a/src/AppContext.tsx
+++ b/src/AppContext.tsx
@@ -1,20 +1,50 @@
import { createContext } from 'react';
import { Domain } from './Api';
+/**
+ * It represents the application context so common events and properties
+ * are shared for many components, making their values accessible.
+ * @public
+ */
export interface IAppContext {
+ /** Represent the current list of domains to be displayed in the listDomains view. */
domains: Domain[];
+ /** Callback to set the value of `domains`. */
setDomains: (domains: Domain[]) => void;
- // wizardDomain?: Domain;
- // setWizardDomain: (domain?: Domain) => void;
+ /** Encapsulates the context related with the wizard. */
+ wizard: {
+ /** Retrieve the current token, required to register a domain. */
+ getToken: () => string;
+ /** Set the value of the token. */
+ setToken: (value: string) => void;
+ /** Get the ephemeral domain state that manage the wizard. */
+ getDomain: () => Domain;
+ /** Set the ephemeral domain information. */
+ setDomain: (value: Domain) => void;
+ };
}
+/**
+ * Represent the application context.
+ * @public
+ */
export const AppContext = createContext({
domains: [],
setDomains: (domains: Domain[]) => {
throw new Error('Function "setDomains" not implemented: domains=' + domains);
},
- // wizardDomain: undefined,
- // setWizardDomain: (domain?: Domain) => {
- // throw new Error('Function "setWizardDomain" not implemented: domain=' + domain);
- // },
+ wizard: {
+ getToken: (): string => {
+ return '';
+ },
+ setToken: (value: string) => {
+ throw new Error('Function "setToken" not implemented: value=' + value);
+ },
+ getDomain: (): Domain => {
+ return {} as Domain;
+ },
+ setDomain: (value: Domain) => {
+ throw new Error('Function "setDomain" not implemented: value=' + value);
+ },
+ },
});
diff --git a/src/AppEntry.tsx b/src/AppEntry.tsx
index 8bf2bf4..4fe8379 100644
--- a/src/AppEntry.tsx
+++ b/src/AppEntry.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useContext, useState } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import { init } from './store';
@@ -9,14 +9,41 @@ import { AppContext } from './AppContext';
import { Domain } from './Api';
const AppEntry = () => {
+ const appContext = useContext(AppContext);
const [domains, setDomains] = useState([]);
+ const [wizardToken, setWizardToken] = useState('');
+ const [wizardDomain, setWizardDomain] = useState({} as Domain);
const cbSetDomains = (domains: Domain[]) => {
+ appContext.domains = domains;
setDomains(domains);
};
+ const cbGetWizardToken = (): string => {
+ return wizardToken;
+ };
+ const cbSetWizardToken = (value: string) => {
+ setWizardToken(value);
+ };
+ const cbGetWizardDomain = (): Domain => {
+ return wizardDomain;
+ };
+ const cbSetWizardDomain = (value: Domain) => {
+ setWizardDomain(value);
+ };
return (
-
+
diff --git a/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.scss b/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.scss
index 219c002..acd9576 100644
--- a/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.scss
+++ b/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.scss
@@ -1,9 +1 @@
@import '~@redhat-cloud-services/frontend-components-utilities/styles/variables';
-
-.domain-type-select {
- width: 50%;
-}
-
-.domain-item-margin-left {
- margin-left: 16px;
-}
diff --git a/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.tsx b/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.tsx
index 511024a..d340d19 100644
--- a/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.tsx
+++ b/src/Routes/WizardPage/Components/PagePreparation/PagePreparation.tsx
@@ -1,26 +1,81 @@
-import React from 'react';
+import React, { useContext, useEffect, useState } from 'react';
import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon';
import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon';
-import { Button, ClipboardCopy, Form, FormGroup, Icon, Select, SelectOption, Stack, TextContent } from '@patternfly/react-core';
+import { Button, ClipboardCopy, Form, FormGroup, Icon, Select, SelectOption, TextContent, Title } from '@patternfly/react-core';
import './PagePreparation.scss';
+import { DomainType, ResourcesApiFactory } from '../../../../Api';
+import { AppContext, IAppContext } from '../../../../AppContext';
-const PagePreparation: React.FC = () => {
- // TODO Update links
- const firewallConfigurationLink =
- 'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/using-and-configuring-firewalld_configuring-and-managing-networking';
- const cloudProviderConfigurationLink =
- 'https://access.redhat.com/documentation/es-es/red_hat_subscription_management/2023/html-single/red_hat_cloud_access_reference_guide/index';
- const networkConfigurationLink = 'https://www.redhat.com/sysadmin/network-interface-linux';
- const installServerPackagesLink = 'https://freeipa.org/page/Quick_Start_Guide';
+/** Represent the properties for PagePreparation component. */
+interface PagePreparationProps {
+ token?: string;
+ onToken?: (token: string, domain_id: string, expiration: number) => void;
+}
+
+/**
+ * This page provide information and links to prepare the rhel-idm
+ * servers before the user could proceed to the registration process.
+ * @param props provide the token value and the onToken event to
+ * notify when it is created.
+ * @returns Return the view to inform the user how to prepare for
+ * the domain registration.
+ * @public
+ * @see {@link PagePreparationProps} to know about the properties.
+ * @see {@link WizardPage} to know about the parent component.
+ */
+const PagePreparation = (props: PagePreparationProps) => {
+ // FIXME Update the target link when it is known
+ const installServerPackagesLink = 'https://duckduckgo.com/?q=freeipa+prerequisites';
+ // FIXME Update the target link when it is known
+ const prerequisitesLink = 'https://www.google.com?q=rhel-idm+pre-requisites';
// States
- const [isOpen, setIsOpen] = React.useState(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const appContext = useContext(AppContext);
+
+ const base_url = '/api/idmsvc/v1';
+ const resources_api = ResourcesApiFactory(undefined, base_url, undefined);
+
+ const token = appContext.wizard.getToken();
+ const domain = appContext.wizard.getDomain();
+ const domain_id = domain.domain_id ? domain.domain_id : '';
+
+ /**
+ * side effect to retrieve a token in the background.
+ * TODO When more than one type of domain, this callback will
+ * invoke from 'onRegisterDomainTypeSelect' event.
+ */
+ useEffect(() => {
+ if (token != '' && domain_id != '') {
+ return;
+ }
+ // NOTE await and async cannot be used directly because EffectCallback cannot be a Promise
+ resources_api
+ .createDomainToken({ domain_type: 'rhel-idm' }, undefined, undefined)
+ .then((value) => {
+ appContext.wizard.setToken(value.data.domain_token);
+ const domain_id = value.data.domain_id;
+ const domain_name = 'My domain';
+ const domain_type = value.data.domain_type;
+ const token = value.data.domain_token;
+ const expiration = value.data.expiration;
+ appContext.wizard.setDomain({
+ domain_id: domain_id,
+ domain_name: domain_name,
+ domain_type: domain_type,
+ });
+ props.onToken?.(token, domain_id, expiration);
+ })
+ .catch((reason) => {
+ // FIXME handle the error here
+ console.log('error creating the token by createDomainToken: ' + reason);
+ });
+ }, [token, domain_id]);
- // hooks
const onRegisterDomainTypeSelect = () => {
- // TODO Not implemented
- console.debug('onRegisterDomainTypeSelect in WizardPage');
+ // TODO Not implemented, currently only support rhel-idm
+ console.debug('PagePreparation.onRegisterDomainTypeSelect in WizardPage');
return;
};
@@ -30,29 +85,29 @@ const PagePreparation: React.FC = () => {
const domainOptions = [
{
- value: 'rhel-idm',
- title: 'Red Hat Enterprise Linux IdM/IPA',
+ value: 'rhel-idm' as DomainType,
+ title: 'RHEL IdM (IPA)',
},
];
return (
-
+ <>
+ Preparation for your directory and domain service
-
+ >
);
};
diff --git a/src/Routes/WizardPage/WizardPage.tsx b/src/Routes/WizardPage/WizardPage.tsx
index a8edb05..7699ed1 100644
--- a/src/Routes/WizardPage/WizardPage.tsx
+++ b/src/Routes/WizardPage/WizardPage.tsx
@@ -1,13 +1,20 @@
-import React, { useEffect, useState } from 'react';
+/**
+ * This library implement the WizardPage.
+ *
+ * The goal is provide the steps to register and add
+ * a new domain service.
+ */
+import React, { useContext, useState } from 'react';
import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon';
-import { Button, Page, PageSection, PageSectionTypes, PageSectionVariants, Wizard } from '@patternfly/react-core';
+import { Button, Page, PageSection, PageSectionTypes, PageSectionVariants, Wizard, WizardStep } from '@patternfly/react-core';
import { PageHeader, PageHeaderTitle } from '@redhat-cloud-services/frontend-components/PageHeader';
import './WizardPage.scss';
import { useNavigate } from 'react-router-dom';
-import { Domain } from '../../Api/api';
+import { Domain, ResourcesApiFactory } from '../../Api/api';
+import { AppContext } from '../../AppContext';
// Lazy load for the wizard pages
const PagePreparation = React.lazy(() => import('./Components/PagePreparation/PagePreparation'));
@@ -33,57 +40,119 @@ const initialDomain: Domain = {
/**
* Wizard page to register a new domain into the service.
+ * @see {@link PagePreparation} about the preparation page.
+ * @see {@link PageServiceRegistration} about the registration page.
+ * @see {@link PageServiceDetails} about the details page.
+ * @see {@link PageReview} about the review page.
*/
-const WizardPage: React.FC = () => {
+const WizardPage = () => {
+ const base_url = '/api/idmsvc/v1';
+ const resources_api = ResourcesApiFactory(undefined, base_url, undefined);
+ const appContext = useContext(AppContext);
+ const domain = appContext.wizard.getDomain();
const navigate = useNavigate();
- // TODO Update the initial state into the context so that
- // state can be read/write from the different pages
- // into the wizard process.
- const [data] = useState(initialDomain);
-
- useEffect(() => {
- insights?.chrome?.appAction?.('default-page');
- }, []);
-
// FIXME Update the URL with the location for docs
const linkLearnMoreAbout = 'https://access.redhat.com/articles/1586893';
- // Event when Close button is clicked
+ /** Event triggered when Close button is clicked. */
const onCloseClick = () => {
- // TODO Not implemented
- // What happens on Cancel? (see documentation)
+ // FIXME A few things pending:
+ // - Mocal confirmation
+ // - Confirm =>
+ // - if not registered, dismiss wizard
+ // - else => DELETE /domains/:domain_id
+ // - Cancel or close model => Do not dismiss wizard
navigate('/domains');
};
+ /** Event triggered when Back button is clicked. */
+ const onPreviousPage = (
+ _newStep: { id?: string | number; name: React.ReactNode },
+ _prevStep: { prevId?: string | number; prevName: React.ReactNode }
+ ) => {
+ console.log('onPreviousPage fired');
+ return;
+ };
+
+ /** Event triggered when a specific page is clicked. */
+ const onGoToStep = (
+ _newStep: { id?: string | number; name: React.ReactNode },
+ _prevStep: { prevId?: string | number; prevName: React.ReactNode }
+ ) => {
+ console.log('onGoToStep fired');
+ return;
+ };
+
+ /** Event triggered when the Next button is clicked. */
+ const onNextPage = async ({ id }: WizardStep) => {
+ // FIXME Delete log
+ console.log('onNextPage fired for id=' + id);
+ if (id === undefined) {
+ return;
+ }
+ if (typeof id === 'string') {
+ const [, orderIndex] = id.split('-');
+ id = parseInt(orderIndex);
+ }
+ };
+
+ const initCanJumpPage1 = true;
+ const initCanJumpPage2 = initCanJumpPage1 && domain.domain_id != '' && appContext.wizard.getToken() != '';
+ const initCanJumpPage3 = initCanJumpPage2;
+ const initCanJumpPage4 = initCanJumpPage3 && domain.title !== undefined && domain.title.length > 0;
+
+ const [canJumpPage1] = useState(initCanJumpPage1);
+ const [canJumpPage2, setCanJumpPage2] = useState(initCanJumpPage2);
+ const [canJumpPage3, setCanJumpPage3] = useState(initCanJumpPage3);
+ const [canJumpPage4, setCanJumpPage4] = useState(initCanJumpPage4);
+
+ const onToken = (token: string, domain_id: string, expiration: number) => {
+ console.log('WizardPage.OnToken fired: token=' + token + '; domain_id=' + domain_id + '; expiration=' + expiration);
+ if (token != '') {
+ setCanJumpPage2(true);
+ } else {
+ setCanJumpPage2(false);
+ }
+ };
+
+ /** Configure the wizard pages. */
const steps = [
{
// This page only display the pre-requisites
+ id: 1,
name: 'Preparation',
- component: ,
+ component: ,
+ canJumpTo: canJumpPage1,
},
{
+ id: 2,
name: 'Service registration',
// FIXME Pass here the 'registering.domain' field from the context
// FIXME Pass here the 'registering.token' field from the context
- component: ,
+ component: ,
+ canJumpTo: canJumpPage2,
},
{
+ id: 3,
name: 'Service details',
// FIXME Pass here the 'registering.domain' field from the context
- component: ,
+ component: ,
+ canJumpTo: canJumpPage3,
},
{
+ id: 4,
name: 'Review',
// FIXME Pass here the 'registering.domain' field from the context
- component: ,
+ component: ,
+ canJumpTo: canJumpPage4,
},
];
const title = 'Register directory and domain service';
return (
-
+ <>
@@ -98,7 +167,7 @@ const WizardPage: React.FC = () => {
iconPosition="right"
href={linkLearnMoreAbout}
>
- Learn more about the directory and domain services.
+ Learn more about the directory and domain services{' '}
@@ -106,7 +175,7 @@ const WizardPage: React.FC = () => {
-
+ >
);
};