Skip to content

Commit

Permalink
Add /groups/%id route and the page component
Browse files Browse the repository at this point in the history
  • Loading branch information
gkarat committed Feb 21, 2023
1 parent 8eec311 commit a010397
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down Expand Up @@ -51,6 +53,15 @@ export const Routes = () => {
}
rootClass="inventory"
/>
<Route exact path={routes.groupDetail} component={groupsEnabled
? InventoryGroupDetail
: () => (
<EmptyState>
<EmptyStateBody>
<InvalidObject />
</EmptyStateBody>
</EmptyState>
)} rootClass='inventory' />
<Route exact path={routes.detailWithModal} component={InventoryDetail} rootClass='inventory' />
<Route exact path={routes.detail} component={InventoryDetail} rootClass='inventory' />
<Redirect path="*" to="/" />
Expand Down
35 changes: 35 additions & 0 deletions src/components/InventoryGroupDetail/GroupDetailHeader.js
Original file line number Diff line number Diff line change
@@ -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 ? (
<Skeleton width="250px" screenreaderText="Loading group details" />
) : (
// in case of error, render just id from URL
data?.name || groupId
);

return (
<PageHeader>
<Breadcrumb>
<BreadcrumbItem>
<Link to={routes.groups}>Groups</Link>
</BreadcrumbItem>
<BreadcrumbItem isActive>{nameOrId}</BreadcrumbItem>
</Breadcrumb>
<PageHeaderTitle title={nameOrId} />
</PageHeader>
);
};

export default GroupDetailHeader;
20 changes: 20 additions & 0 deletions src/components/InventoryGroupDetail/GroupDetailInfo.js
Original file line number Diff line number Diff line change
@@ -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 (
<EmptyState>
<EmptyStateBody>
{uninitialized || loading ? <Spinner /> : <InvalidObject />}
</EmptyStateBody>
</EmptyState>
);
};

export default GroupDetailInfo;
22 changes: 22 additions & 0 deletions src/components/InventoryGroupDetail/GroupDetailSystems.js
Original file line number Diff line number Diff line change
@@ -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 ?
<EmptyState>
<EmptyStateBody>
<Spinner />
</EmptyStateBody>
</EmptyState>
: <NoSystemsEmptyState />

);
};

export default GroupDetailSystems;
60 changes: 60 additions & 0 deletions src/components/InventoryGroupDetail/InventoryGroupDetail.js
Original file line number Diff line number Diff line change
@@ -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 (
<React.Fragment>
<GroupDetailHeader />
<PageSection variant='light' type='tabs'>
<Tabs
activeKey={activeTabKey}
onSelect={(event, value) => setActiveTabKey(value)}
aria-label="Group tabs"
role="region"
inset={{ default: 'insetMd' }} // add extra space before the first tab (according to mocks)
>
<Tab eventKey={0} title={<TabTitleText>Systems</TabTitleText>} aria-label="Group systems tab">
<PageSection>
<GroupDetailSystems />
</PageSection>
</Tab>
<Tab eventKey={1} title={<TabTitleText>Group info</TabTitleText>} aria-label="Group info tab">
<PageSection>
<GroupDetailInfo />
</PageSection>
</Tab>
</Tabs>

</PageSection>
</React.Fragment>
);
};

export default InventoryGroupDetail;
42 changes: 42 additions & 0 deletions src/components/InventoryGroupDetail/NoSystemsEmptyState.js
Original file line number Diff line number Diff line change
@@ -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 (
<EmptyState
data-ouia-component-id="empty-state"
data-ouia-component-type="PF4/EmptyState"
data-ouia-safe={true}
>
<EmptyStateIcon icon={PlusCircleIcon} color={globalPaletteBlack600.value} />
<Title headingLevel="h4" size="lg">
No systems added
</Title>
<EmptyStateBody>
To manage systems more effectively, add systems to the group.
</EmptyStateBody>
<Button variant="primary" onClick={() => {}}>Add systems</Button>
<EmptyStateSecondaryActions>
<Button
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
// TODO: component={(props) => <a href='' {...props} />}
>
Learn more about system groups
</Button>
</EmptyStateSecondaryActions>
</EmptyState>
);};

export default NoSystemsEmptyState;
3 changes: 3 additions & 0 deletions src/components/InventoryGroupDetail/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import InventoryGroupDetail from './InventoryGroupDetail';

export default InventoryGroupDetail;
3 changes: 3 additions & 0 deletions src/routes/InventoryGroupDetail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import InventoryGroupDetail from '../components/InventoryGroupDetail';

export default InventoryGroupDetail;

0 comments on commit a010397

Please sign in to comment.