diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js
new file mode 100644
index 000000000..149f934ab
--- /dev/null
+++ b/src/components/InventoryGroupDetail/GroupTabDetails.js
@@ -0,0 +1,101 @@
+import {
+ Bullseye,
+ PageSection,
+ Spinner,
+ Tab,
+ TabTitleText,
+ Tabs,
+} from '@patternfly/react-core';
+import React, { Suspense, lazy, useState } from 'react';
+import { hybridInventoryTabKeys } from '../../Utilities/constants';
+import GroupSystems from '../GroupSystems';
+import PropTypes from 'prop-types';
+import { usePermissionsWithContext } from '@redhat-cloud-services/frontend-components-utilities/RBACHook';
+import { REQUIRED_PERMISSIONS_TO_READ_GROUP_HOSTS } from '../../constants';
+import EdgeDeviceGroupiew from '../InventoryTabs/ImmutableDevices/EdgeDevicesGroupView';
+import { EmptyStateNoAccessToSystems } from './EmptyStateNoAccess';
+
+const GroupDetailInfo = lazy(() => import('./GroupDetailInfo'));
+
+const GroupTabDetailsWrapper = ({
+ groupId,
+ groupName,
+ activeTab,
+ hasEdgeImages,
+}) => {
+ const [tab, setTab] = useState(0);
+ const { hasAccess: canViewHosts } = usePermissionsWithContext(
+ REQUIRED_PERMISSIONS_TO_READ_GROUP_HOSTS(groupId)
+ );
+
+ const handleTabClick = (_event, tabIndex) => {
+ setTab(tabIndex);
+ };
+
+ 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)
+ mountOnEnter
+ unmountOnExit
+ >
+
+
+ {canViewHosts && hasEdgeImages ? (
+
+ Conventional (RPM-DNF)}
+ >
+
+
+ Immutable (OSTree)}
+ >
+
+
+
+ ) : canViewHosts ? (
+
+ ) : (
+
+ )}
+
+
+
+ {activeTabKey === 1 && ( // helps to lazy load the component
+
+
+
+
+ }
+ >
+
+
+
+ )}
+
+
+ );
+};
+
+GroupTabDetailsWrapper.propTypes = {
+ groupName: PropTypes.string.isRequired,
+ groupId: PropTypes.string.isRequired,
+ activeTab: PropTypes.string,
+ hasEdgeImages: PropTypes.bool,
+};
+export default GroupTabDetailsWrapper;
diff --git a/src/components/InventoryGroupDetail/InventoryGroupDetail.js b/src/components/InventoryGroupDetail/InventoryGroupDetail.js
index 34015fd3a..09bd4487d 100644
--- a/src/components/InventoryGroupDetail/InventoryGroupDetail.js
+++ b/src/components/InventoryGroupDetail/InventoryGroupDetail.js
@@ -11,6 +11,7 @@ import React, { Suspense, lazy, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchGroupDetail } from '../../store/inventory-actions';
import GroupSystems from '../GroupSystems';
+import GroupTabDetails from './GroupTabDetails';
import GroupDetailHeader from './GroupDetailHeader';
import { usePermissionsWithContext } from '@redhat-cloud-services/frontend-components-utilities/RBACHook';
import {
@@ -21,10 +22,35 @@ import {
EmptyStateNoAccessToGroup,
EmptyStateNoAccessToSystems,
} from './EmptyStateNoAccess';
+import useFeatureFlag from '../../Utilities/useFeatureFlag';
+import axios from 'axios';
+import {
+ INVENTORY_TOTAL_FETCH_CONVENTIONAL_PARAMS,
+ INVENTORY_TOTAL_FETCH_EDGE_PARAMS,
+ INVENTORY_TOTAL_FETCH_URL_SERVER,
+ hybridInventoryTabKeys,
+} from '../../Utilities/constants';
-const GroupDetailInfo = lazy(() => import('./GroupDetailInfo'));
+const SuspenseWrapper = ({ children }) => (
+
+
+
+ }
+ >
+ {children}
+
+);
+const GroupDetailInfo = lazy(() => import('./GroupDetailInfo'));
const InventoryGroupDetail = ({ groupId }) => {
+ const [activeTabKey, setActiveTabKey] = useState(0);
+
+ const [activeTab, setActiveTab] = useState(
+ hybridInventoryTabKeys.conventional.key
+ );
+
const dispatch = useDispatch();
const { data } = useSelector((state) => state.groupDetail);
const chrome = useChrome();
@@ -33,7 +59,6 @@ const InventoryGroupDetail = ({ groupId }) => {
const { hasAccess: canViewGroup } = usePermissionsWithContext(
REQUIRED_PERMISSIONS_TO_READ_GROUP(groupId)
);
-
const { hasAccess: canViewHosts } = usePermissionsWithContext(
REQUIRED_PERMISSIONS_TO_READ_GROUP_HOSTS(groupId)
);
@@ -51,11 +76,59 @@ const InventoryGroupDetail = ({ groupId }) => {
);
}, [data]);
- const [activeTabKey, setActiveTabKey] = useState(0);
-
// TODO: append search parameter to identify the active tab
- return (
+ const [hasEdgeImages, setHasEdgeImages] = useState(false);
+ const EdgeParityEnabled = useFeatureFlag('edgeParity.inventory-list');
+ useEffect(() => {
+ if (EdgeParityEnabled) {
+ try {
+ axios
+ .get(
+ `${INVENTORY_TOTAL_FETCH_URL_SERVER}${INVENTORY_TOTAL_FETCH_EDGE_PARAMS}&group_name=${groupName}`
+ )
+ .then((result) => {
+ const accountHasEdgeImages = result?.data?.total > 0;
+ setHasEdgeImages(accountHasEdgeImages);
+ axios
+ .get(
+ `${INVENTORY_TOTAL_FETCH_URL_SERVER}${INVENTORY_TOTAL_FETCH_CONVENTIONAL_PARAMS}&group_name=${groupName}`
+ )
+ .then((conventionalImages) => {
+ const accountHasConventionalImages =
+ conventionalImages?.data?.total > 0;
+ if (accountHasEdgeImages && !accountHasConventionalImages) {
+ setActiveTab(hybridInventoryTabKeys.immutable.key);
+ } else {
+ setActiveTab(hybridInventoryTabKeys.conventional.key);
+ }
+ });
+ });
+ } catch (e) {
+ setHasEdgeImages(false);
+ setActiveTab(hybridInventoryTabKeys.conventional.key);
+ }
+ }
+ }, [data]);
+ return hasEdgeImages && canViewGroup && EdgeParityEnabled ? (
+
+
+ {canViewGroup ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+ ) : (
{canViewGroup ? (
@@ -104,6 +177,11 @@ const InventoryGroupDetail = ({ groupId }) => {
InventoryGroupDetail.propTypes = {
groupId: PropTypes.string.isRequired,
+ groupName: PropTypes.string,
+};
+
+SuspenseWrapper.propTypes = {
+ children: PropTypes.element,
};
export default InventoryGroupDetail;
diff --git a/src/components/InventoryTabs/ImmutableDevices/EdgeDevicesGroupView.js b/src/components/InventoryTabs/ImmutableDevices/EdgeDevicesGroupView.js
new file mode 100644
index 000000000..0bb8b6ac2
--- /dev/null
+++ b/src/components/InventoryTabs/ImmutableDevices/EdgeDevicesGroupView.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent';
+import ErrorState from '@redhat-cloud-services/frontend-components/ErrorState';
+import { resolveRelPath } from '../../../Utilities/path';
+import {
+ getNotificationProp,
+ manageEdgeInventoryUrlName,
+} from '../../../Utilities/edge';
+import { useLocation, useNavigate } from 'react-router-dom';
+import { useDispatch } from 'react-redux';
+
+const EdgeDeviceGroupiew = (props) => {
+ const dispatch = useDispatch();
+ const notificationProp = getNotificationProp(dispatch);
+ return (
+ }
+ navigateProp={useNavigate}
+ locationProp={useLocation}
+ showHeaderProp={false}
+ pathPrefix={resolveRelPath('')}
+ urlName={manageEdgeInventoryUrlName}
+ notificationProp={notificationProp}
+ {...props}
+ />
+ );
+};
+
+export default EdgeDeviceGroupiew;