Skip to content

Commit

Permalink
HMS-1623 feat: update reviewed detail view
Browse files Browse the repository at this point in the history
This change update the UI changes for the details view for a given
registered domain.

Signed-off-by: Alejandro Visiedo <[email protected]>
  • Loading branch information
avisiedo committed Oct 30, 2023
1 parent 2469974 commit 8801822
Show file tree
Hide file tree
Showing 10 changed files with 468 additions and 214 deletions.
16 changes: 14 additions & 2 deletions src/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import { VerifyState } from './Routes/WizardPage/Components/VerifyRegistry/Verif
*/
export interface IAppContext {
/** Represent the current list of domains to be displayed in the listDomains view. */
domains: Domain[];
getDomains: () => Domain[];
/** Callback to set the value of `domains`. */
setDomains: (domains: Domain[]) => void;
/** The current editing domain */
getEditing: () => Domain | undefined;
/** Set the current editing domain */
setEditing: (value: Domain | undefined) => void;
/** Encapsulates the context related with the wizard. */
wizard: {
/** Retrieve the current token, required to register a domain. */
Expand All @@ -35,10 +39,18 @@ export interface IAppContext {
* @public
*/
export const AppContext = createContext<IAppContext>({
domains: [],
getDomains: (): Domain[] => {
return [];
},
setDomains: (domains: Domain[]) => {
throw new Error('Function "setDomains" not implemented: domains=' + domains);
},
getEditing: (): Domain | undefined => {
return undefined;
},
setEditing: (value: Domain | undefined) => {
throw new Error('Function "setEditing" not implemented: value=' + value);
},
wizard: {
getToken: (): string => {
return '';
Expand Down
19 changes: 15 additions & 4 deletions src/AppEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react';
import React, { useState } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import { init } from './store';
Expand All @@ -10,13 +10,16 @@ import { Domain } from './Api';
import { VerifyState } from './Routes/WizardPage/Components/VerifyRegistry/VerifyRegistry';

const AppEntry = () => {
const appContext = useContext(AppContext);
const [domains, setDomains] = useState<Domain[]>([]);
const [wizardToken, setWizardToken] = useState<string>('');
const [wizardDomain, setWizardDomain] = useState<Domain>({} as Domain);
const [wizardRegisterStatus, setWizardRegisterStatus] = useState<VerifyState>('initial');
const [editing, setEditing] = useState<Domain | undefined>(undefined);

const cbGetDomains = (): Domain[] => {
return domains;
};
const cbSetDomains = (domains: Domain[]) => {
appContext.domains = domains;
setDomains(domains);
};
const cbGetWizardToken = (): string => {
Expand All @@ -37,12 +40,20 @@ const AppEntry = () => {
const cbSetRegisterStatus = (value: VerifyState) => {
setWizardRegisterStatus(value);
};
const cbGetEditing = (): Domain | undefined => {
return editing;
};
const cbSetEditing = (value: Domain | undefined) => {
setEditing(value);
};
return (
<Provider store={init(...(process.env.NODE_ENV !== 'production' ? [logger] : [])).getStore()}>
<Router basename={getBaseName(window.location.pathname)}>
<AppContext.Provider
value={{
domains: domains,
getEditing: cbGetEditing,
setEditing: cbSetEditing,
getDomains: cbGetDomains,
setDomains: cbSetDomains,
wizard: {
getToken: cbGetWizardToken,
Expand Down
22 changes: 19 additions & 3 deletions src/Components/DomainList/DomainList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { Fragment, useContext, useState } from 'react';
import React from 'react';

import { Domain, DomainType, ResourcesApiFactory } from '../../Api/api';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';

Check failure on line 7 in src/Components/DomainList/DomainList.tsx

View workflow job for this annotation

GitHub Actions / validate

'Link' is defined but never used

Check warning on line 7 in src/Components/DomainList/DomainList.tsx

View workflow job for this annotation

GitHub Actions / validate

'Link' is defined but never used
import { AppContext, IAppContext } from '../../AppContext';
import { Button } from '@patternfly/react-core';

export interface IColumnType<T> {
key: string;
Expand Down Expand Up @@ -95,6 +96,7 @@ export const DomainList = () => {
const resources_api = ResourcesApiFactory(undefined, base_url, undefined);

const context = useContext<IAppContext>(AppContext);
const navigate = useNavigate();

// Index of the currently sorted column
// Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key
Expand All @@ -104,7 +106,7 @@ export const DomainList = () => {
// Sort direction of the currently sorted column
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc'>('asc');

const [domains, setDomains] = useState<Domain[]>(context.domains);
const [domains, setDomains] = useState<Domain[]>(context.getDomains());
const enabledText = 'Enabled';
const disabledText = 'Disabled';

Expand Down Expand Up @@ -200,6 +202,13 @@ export const DomainList = () => {
// We shouldn't store the list of data in state because we don't want to have to sync that with props.
activeSortIndex !== null && domains.sort(createCompareRows(activeSortIndex, activeSortDirection));

const onShowDetails = (domain: Domain | undefined) => {
if (domain !== undefined) {
context.setEditing(domain);
navigate('/details/' + domain?.domain_id);
}
};

return (
<>
<TableComposable>
Expand All @@ -223,7 +232,14 @@ export const DomainList = () => {
<>
<Tr key={domain.domain_id}>
<Td>
<Link to={'/details/' + domain.domain_id}>{domain.title}</Link>
<Button
variant="link"
onClick={() => {
onShowDetails(domain);
}}
>
{domain.title}
</Button>
</Td>
<Td>
<DomainListFieldType domain_type={domain.domain_type} />
Expand Down
29 changes: 10 additions & 19 deletions src/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { Suspense, lazy } from 'react';
import React, { lazy } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';

import { Bullseye, Spinner } from '@patternfly/react-core';
import WizardPage from './Routes/WizardPage/WizardPage';
import DetailPage from './Routes/DetailPage/DetailPage';

Expand All @@ -18,23 +17,15 @@ const NoPermissionsPage = lazy(() => import(/* webpackChunkName: "NoPermissionsP
* component - component to be rendered when a route has been chosen.
*/
const DomainRegistryRoutes = () => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<Routes>
<Route path="/domains" Component={DefaultPage} />
<Route path="/details/:domain_id" Component={DetailPage} />
<Route path="/domains/wizard" Component={WizardPage} />
<Route path="/oops" Component={OopsPage} />
<Route path="/no-permissions" Component={NoPermissionsPage} />
{/* Finally, catch all unmatched routes */}
<Route path="*" element={<Navigate to="/domains" replace />} />
</Routes>
</Suspense>
<Routes>
<Route path="/domains" Component={DefaultPage} />
<Route path="/details/:domain_id" Component={DetailPage} />
<Route path="/domains/wizard" Component={WizardPage} />
<Route path="/oops" Component={OopsPage} />
<Route path="/no-permissions" Component={NoPermissionsPage} />
{/* Finally, catch all unmatched routes */}
<Route path="*" element={<Navigate to="/domains" replace />} />
</Routes>
);

export default DomainRegistryRoutes;
60 changes: 31 additions & 29 deletions src/Routes/DefaultPage/DefaultPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
CardBody,
EmptyState,
EmptyStateBody,
EmptyStateIcon,
EmptyStateVariant,
Flex,
FlexItem,
Expand All @@ -34,21 +35,23 @@ const Header = () => {
const title = 'Directory and Domain Services';

return (
<>
<PageHeader>
<PageHeaderTitle title={title} />
<p>
Manage registered identity domains to leverage host access controls from your existing identity and access management.{' '}
<Button component="a" target="_blank" variant="link" isInline icon={<ExternalLinkAltIcon />} iconPosition="right" href={linkLearnMoreAbout}>
Learn more about the domain registry.
</Button>
</p>
</PageHeader>
</>
<PageHeader>
<PageHeaderTitle title={title} />
<p>
Manage registered identity domains to leverage host access controls from your existing identity and access management.{' '}
<Button component="a" target="_blank" variant="link" isInline icon={<ExternalLinkAltIcon />} iconPosition="right" href={linkLearnMoreAbout}>
Learn more about the domain registry.
</Button>
</p>
</PageHeader>
);
};

const EmptyContent = () => {
interface EmptyContentProps {
isLoading: boolean;
}

const EmptyContent = (props: EmptyContentProps) => {

Check warning on line 54 in src/Routes/DefaultPage/DefaultPage.tsx

View workflow job for this annotation

GitHub Actions / validate

'props' is defined but never used
// FIXME Update this link in the future
const linkLearnMoreAbout = 'https://access.redhat.com/articles/1586893';
const navigate = useNavigate();
Expand All @@ -66,7 +69,7 @@ const EmptyContent = () => {
<Section>
<Bullseye>
<EmptyState variant={EmptyStateVariant.full}>
<RegistryIcon className="pf-u-color-200" size="xl" />
<EmptyStateIcon icon={RegistryIcon} />
<Title headingLevel="h2" size="lg" className="pf-u-pt-sm">
No identity domains registered
</Title>
Expand Down Expand Up @@ -117,8 +120,7 @@ const ListContent = () => {

// TODO Extract this code in a hook
useEffect(() => {
// eslint-disable-next-line prefer-const
let local_domains: Domain[] = [];
const local_domains: Domain[] = [];
resources_api
.listDomains(undefined, offset, perPage, undefined)
.then((res) => {
Expand Down Expand Up @@ -220,16 +222,15 @@ const DefaultPage = () => {

// States
const [page, setPage] = useState<number>(0);

Check warning on line 224 in src/Routes/DefaultPage/DefaultPage.tsx

View workflow job for this annotation

GitHub Actions / validate

'page' is assigned a value but never used
const [itemCount, setItemCount] = useState<number>(0);
const [itemCount, setItemCount] = useState<number>(appContext.getDomains().length || -1);
const [perPage] = useState<number>(10);
const [offset, setOffset] = useState<number>(0);

console.log('INFO:DefaultPage render');

// TODO Extract in a hook
useEffect(() => {
// eslint-disable-next-line prefer-const
let local_domains: Domain[] = [];
const local_domains: Domain[] = [];
resources_api
.listDomains(undefined, offset, perPage, undefined)
.then((res) => {
Expand All @@ -239,14 +240,14 @@ const DefaultPage = () => {
.readDomain(item.domain_id)
.then((res_domain) => {
local_domains[count++] = res_domain.data;
if (res.data.data.length == local_domains.length) {
appContext.setDomains(local_domains);
const newOffset = Math.floor((offset + perPage - 1) / perPage) * perPage;
const newPage = newOffset / perPage;
setItemCount(res.data.meta.count);
setOffset(newOffset);
setPage(newPage);
}
// if (res.data.data.length == local_domains.length) {
appContext.setDomains(local_domains);
const newOffset = Math.floor((offset + perPage - 1) / perPage) * perPage;
const newPage = newOffset / perPage;
setItemCount(res.data.meta.count);
setOffset(newOffset);
setPage(newPage);
// }
console.log('INFO:domain list updated');
})
.catch((reason) => {
Expand All @@ -260,7 +261,7 @@ const DefaultPage = () => {
return () => {
// Finalizer
};
}, [page, perPage, offset]);
}, []);

const listContent = (
<>
Expand All @@ -272,11 +273,12 @@ const DefaultPage = () => {
const emptyContent = (
<>
<Header />
<EmptyContent />
<EmptyContent isLoading={itemCount < 0} />
</>
);

const content = itemCount == 0 ? emptyContent : listContent;
// TODO Use similar logic to display a Spinner icon
const content = itemCount <= 0 ? emptyContent : listContent;
return content;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '~@redhat-cloud-services/frontend-components-utilities/styles/variables';
Loading

0 comments on commit 8801822

Please sign in to comment.