diff --git a/src/Routes.js b/src/Routes.js index 39cd166a5..94c19011d 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -9,12 +9,14 @@ import useFeatureFlag from './Utilities/useFeatureFlag'; const InventoryTable = lazy(() => import('./routes/InventoryTable')); const InventoryDetail = lazy(() => import('./routes/InventoryDetail')); const InventoryGroups = lazy(() => import('./routes/InventoryGroups')); +const InventoryGroupDetail = lazy(() => import('./routes/InventoryGroupDetail')); export const routes = { table: '/', detail: '/:inventoryId', detailWithModal: '/:inventoryId/:modalId', - groups: '/groups' + groups: '/groups', + groupDetail: '/groups/:groupId' }; export const Routes = () => { @@ -51,6 +53,15 @@ export const Routes = () => { } rootClass="inventory" /> + ( + + + + + + )} rootClass='inventory' /> diff --git a/src/components/InventoryGroupDetail/GroupDetailHeader.js b/src/components/InventoryGroupDetail/GroupDetailHeader.js new file mode 100644 index 000000000..81b8326cc --- /dev/null +++ b/src/components/InventoryGroupDetail/GroupDetailHeader.js @@ -0,0 +1,35 @@ +import { Breadcrumb, BreadcrumbItem, Skeleton } from '@patternfly/react-core'; +import { + PageHeader, + PageHeaderTitle +} from '@redhat-cloud-services/frontend-components'; +import React from 'react'; +import { useSelector } from 'react-redux'; +import { Link, useParams } from 'react-router-dom'; +import { routes } from '../../Routes'; + +const GroupDetailHeader = () => { + const { uninitialized, loading, data } = useSelector((state) => state.groupDetail); + const { groupId } = useParams(); + + const nameOrId = uninitialized || loading ? ( + + ) : ( + // in case of error, render just id from URL + data?.name || groupId + ); + + return ( + + + + Groups + + {nameOrId} + + + + ); +}; + +export default GroupDetailHeader; diff --git a/src/components/InventoryGroupDetail/GroupDetailInfo.js b/src/components/InventoryGroupDetail/GroupDetailInfo.js new file mode 100644 index 000000000..01a935077 --- /dev/null +++ b/src/components/InventoryGroupDetail/GroupDetailInfo.js @@ -0,0 +1,20 @@ +import { EmptyState, EmptyStateBody, Spinner } from '@patternfly/react-core'; +import { InvalidObject } from '@redhat-cloud-services/frontend-components'; +import React from 'react'; +import { useSelector } from 'react-redux'; + +const GroupDetailInfo = () => { + const { uninitialized, loading } = useSelector((state) => state.groupDetail); + + // TODO: implement according to mocks + + return ( + + + {uninitialized || loading ? : } + + + ); +}; + +export default GroupDetailInfo; diff --git a/src/components/InventoryGroupDetail/GroupDetailSystems.js b/src/components/InventoryGroupDetail/GroupDetailSystems.js new file mode 100644 index 000000000..e9470ce71 --- /dev/null +++ b/src/components/InventoryGroupDetail/GroupDetailSystems.js @@ -0,0 +1,22 @@ +import { EmptyState, EmptyStateBody, Spinner } from '@patternfly/react-core'; +import React from 'react'; +import { useSelector } from 'react-redux'; +import NoSystemsEmptyState from './NoSystemsEmptyState'; + +const GroupDetailSystems = () => { + const { uninitialized, loading } = useSelector((state) => state.groupDetail); + + // TODO: integrate the inventory table + + return (uninitialized || loading ? + + + + + + : + + ); +}; + +export default GroupDetailSystems; diff --git a/src/components/InventoryGroupDetail/InventoryGroupDetail.js b/src/components/InventoryGroupDetail/InventoryGroupDetail.js new file mode 100644 index 000000000..fc18f6e43 --- /dev/null +++ b/src/components/InventoryGroupDetail/InventoryGroupDetail.js @@ -0,0 +1,60 @@ +import React, { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import useChrome from '@redhat-cloud-services/frontend-components/useChrome'; +import { useDispatch, useSelector } from 'react-redux'; +import { fetchGroupDetail } from '../../store/inventory-actions'; +import { PageSection, Tab, Tabs, TabTitleText } from '@patternfly/react-core'; +import { useState } from 'react'; +import GroupDetailHeader from './GroupDetailHeader'; +import GroupDetailSystems from './GroupDetailSystems'; +import GroupDetailInfo from './GroupDetailInfo'; + +const InventoryGroupDetail = () => { + const dispatch = useDispatch(); + const { data } = useSelector((state) => state.groupDetail); + const chrome = useChrome(); + + const { groupId } = useParams(); + + useEffect(() => { + dispatch(fetchGroupDetail(groupId)); + }, []); + + useEffect(() => { + // if available, change ID to the group's name in the window title + chrome.updateDocumentTitle( + `${data?.name || groupId} - Inventory Groups | Red Hat Insights` + ); + }, [data]); + + const [activeTabKey, setActiveTabKey] = useState(0); + + return ( + + + + setActiveTabKey(value)} + aria-label="Group tabs" + role="region" + inset={{ default: 'insetMd' }} // add extra space before the first tab (according to mocks) + > + Systems} aria-label="Group systems tab"> + + + + + Group info} aria-label="Group info tab"> + + + + + + + + + ); +}; + +export default InventoryGroupDetail; diff --git a/src/components/InventoryGroupDetail/NoSystemsEmptyState.js b/src/components/InventoryGroupDetail/NoSystemsEmptyState.js new file mode 100644 index 000000000..decc11181 --- /dev/null +++ b/src/components/InventoryGroupDetail/NoSystemsEmptyState.js @@ -0,0 +1,42 @@ +import React from 'react'; +import { + Button, + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStateSecondaryActions, + Title +} from '@patternfly/react-core'; +import { ExternalLinkAltIcon, PlusCircleIcon } from '@patternfly/react-icons'; + +import { global_palette_black_600 as globalPaletteBlack600 } from '@patternfly/react-tokens/dist/js/global_palette_black_600'; + +const NoSystemsEmptyState = () => { + return ( + + + + No systems added + + + To manage systems more effectively, add systems to the group. + + + + + + + );}; + +export default NoSystemsEmptyState; diff --git a/src/components/InventoryGroupDetail/index.js b/src/components/InventoryGroupDetail/index.js new file mode 100644 index 000000000..a3695ffa0 --- /dev/null +++ b/src/components/InventoryGroupDetail/index.js @@ -0,0 +1,3 @@ +import InventoryGroupDetail from './InventoryGroupDetail'; + +export default InventoryGroupDetail; diff --git a/src/routes/InventoryGroupDetail.js b/src/routes/InventoryGroupDetail.js new file mode 100644 index 000000000..235b9c98f --- /dev/null +++ b/src/routes/InventoryGroupDetail.js @@ -0,0 +1,3 @@ +import InventoryGroupDetail from '../components/InventoryGroupDetail'; + +export default InventoryGroupDetail;