Skip to content

Commit

Permalink
Merge branch 'master' into RBAC3
Browse files Browse the repository at this point in the history
  • Loading branch information
adonispuente authored Oct 18, 2023
2 parents 45e2ae1 + b5299c0 commit bf61d25
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 20 deletions.
18 changes: 17 additions & 1 deletion src/Utilities/edge.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import axios from 'axios';
import {
INVENTORY_TOTAL_FETCH_EDGE_PARAMS,
INVENTORY_TOTAL_FETCH_URL_SERVER,
} from './constants';

const manageEdgeInventoryUrlName = 'manage-edge-inventory';

Expand Down Expand Up @@ -43,4 +48,15 @@ const getNotificationProp = (dispatch) => {
};
};

export { getNotificationProp, manageEdgeInventoryUrlName };
const inventoryHasEdgeSystems = async () => {
const result = await axios.get(
`${INVENTORY_TOTAL_FETCH_URL_SERVER}${INVENTORY_TOTAL_FETCH_EDGE_PARAMS}`
);
return result?.data?.total > 0;
};

export {
getNotificationProp,
manageEdgeInventoryUrlName,
inventoryHasEdgeSystems,
};
1 change: 1 addition & 0 deletions src/components/InventoryGroupDetail/NoSystemsEmptyState.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const NoSystemsEmptyState = ({ groupId, groupName }) => {
setIsModalOpen={setIsModalOpen}
groupId={groupId}
groupName={groupName}
edgeParityIsAllowed={true}
/>
<EmptyStateIcon
icon={PlusCircleIcon}
Expand Down
153 changes: 134 additions & 19 deletions src/components/InventoryGroups/Modals/AddSystemsToGroupModal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { Alert, Button, Flex, FlexItem, Modal } from '@patternfly/react-core';
import {
Alert,
Button,
Flex,
FlexItem,
Label,
Modal,
Tab,
TabTitleText,
Tabs,
} from '@patternfly/react-core';
import { TableVariant } from '@patternfly/react-table';
import PropTypes from 'prop-types';
import React, { useCallback, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
clearFilters,
Expand All @@ -16,12 +26,18 @@ import ConfirmSystemsAddModal from './ConfirmSystemsAddModal';
import { useBulkSelectConfig } from '../../../Utilities/hooks/useBulkSelectConfig';
import difference from 'lodash/difference';
import map from 'lodash/map';
import ImmutableDevicesView from '../../InventoryTabs/ImmutableDevices/EdgeDevicesView';
import useFeatureFlag from '../../../Utilities/useFeatureFlag';
import { PageHeaderTitle } from '@redhat-cloud-services/frontend-components/PageHeader';
import { InfoCircleIcon } from '@patternfly/react-icons';
import { inventoryHasEdgeSystems } from '../../../Utilities/edge';

const AddSystemsToGroupModal = ({
isModalOpen,
setIsModalOpen,
groupId,
groupName,
edgeParityIsAllowed,
}) => {
const dispatch = useDispatch();

Expand All @@ -32,7 +48,6 @@ const AddSystemsToGroupModal = ({
);
const rows = useSelector(({ entities }) => entities?.rows || []);

const noneSelected = selected.size === 0;
const total = useSelector(({ entities }) => entities?.total);
const displayedIds = map(rows, 'id');
const pageSelected =
Expand All @@ -55,7 +70,6 @@ const AddSystemsToGroupModal = ({
);
}
);
const showWarning = alreadyHasGroup.length > 0;

const handleSystemAddition = useCallback(
(hostIds) => {
Expand Down Expand Up @@ -92,14 +106,81 @@ const AddSystemsToGroupModal = ({
dispatch(clearFilters());
};

const edgeParityInventoryListEnabled = useFeatureFlag(
'edgeParity.inventory-list'
);
const edgeParityInventoryGroupsEnabled = useFeatureFlag(
'edgeParity.inventory-groups-enabled'
);
const edgeParityEnabled =
edgeParityIsAllowed &&
edgeParityInventoryListEnabled &&
edgeParityInventoryGroupsEnabled;

const [selectedImmutableDevices, setSelectedImmutableDevices] = useState([]);
const selectedImmutableKeys = selectedImmutableDevices.map(
(immutableDevice) => immutableDevice.id
);

// overallSelectedKeys is the list of the conventional and immutable systems ids
const overallSelectedKeys = [...selected.keys(), ...selectedImmutableKeys];
// noneSelected a boolean showing that no system is selected
const noneSelected = overallSelectedKeys.length === 0;

const immutableDevicesAlreadyHasGroup = selectedImmutableDevices.filter(
(immutableDevice) => immutableDevice.deviceGroups?.length > 0
);
// showWarning when conventional or immutable systems had groups
const showWarning =
alreadyHasGroup.length > 0 || immutableDevicesAlreadyHasGroup.length > 0;

const [hasImmutableSystems, setHasImmutableSystems] = useState(false);

useEffect(() => {
if (edgeParityEnabled) {
(async () => {
const hasEdgeSystems = await inventoryHasEdgeSystems();
setHasImmutableSystems(hasEdgeSystems);
})();
}
}, []);

const [activeTab, setActiveTab] = useState(0);

const handleTabClick = (_event, tabIndex) => {
setActiveTab(tabIndex);
};

let overallSelectedText;
if (overallSelectedKeys.length === 1) {
overallSelectedText = '1 system selected';
} else if (overallSelectedKeys.length > 1) {
overallSelectedText = `${overallSelectedKeys.length} systems selected`;
}

const ConventionalInventoryTable = (
<InventoryTable
columns={(columns) => prepareColumns(columns, false, true)}
variant={TableVariant.compact} // TODO: this doesn't affect the table variant
tableProps={{
isStickyHeader: false,
canSelectAll: false,
}}
bulkSelect={bulkSelectConfig}
initialLoading={true}
showTags
showCentosVersions
/>
);

return (
isModalOpen && (
<>
{/** confirmation modal */}
<ConfirmSystemsAddModal
isModalOpen={confirmationModalOpen}
onSubmit={async () => {
await handleSystemAddition([...selected.keys()]);
await handleSystemAddition(overallSelectedKeys);
setTimeout(() => dispatch(fetchGroupDetail(groupId)), 500); // refetch data for this group
setIsModalOpen(false);
}}
Expand All @@ -112,7 +193,24 @@ const AddSystemsToGroupModal = ({
/>
{/** hosts selection modal */}
<Modal
title="Add systems"
header={
<Flex direction={{ default: 'row' }} style={{ width: '100%' }}>
<FlexItem align={{ default: 'alignLeft' }}>
<PageHeaderTitle title={'Add systems'} />
</FlexItem>
{edgeParityEnabled && !noneSelected && (
<FlexItem align={{ default: 'alignRight' }}>
<Label
variant="outline"
color="blue"
icon={<InfoCircleIcon />}
>
{overallSelectedText}
</Label>
</FlexItem>
)}
</Flex>
}
isOpen={systemsSelectModalOpen}
onClose={() => handleModalClose()}
footer={
Expand All @@ -135,7 +233,7 @@ const AddSystemsToGroupModal = ({
setSystemSelectModalOpen(false);
setConfirmationModalOpen(true); // switch to the confirmation modal
} else {
await handleSystemAddition([...selected.keys()]);
await handleSystemAddition(overallSelectedKeys);
dispatch(fetchGroupDetail(groupId));
handleModalClose();
}
Expand All @@ -156,18 +254,34 @@ const AddSystemsToGroupModal = ({
}
variant="large" // required to accomodate the systems table
>
<InventoryTable
columns={(columns) => prepareColumns(columns, false, true)}
variant={TableVariant.compact} // TODO: this doesn't affect the table variant
tableProps={{
isStickyHeader: false,
canSelectAll: false,
}}
bulkSelect={bulkSelectConfig}
initialLoading={true}
showTags
showCentosVersions
/>
{edgeParityEnabled && hasImmutableSystems ? (
<Tabs
className="pf-m-light pf-c-table"
activeKey={activeTab}
onSelect={handleTabClick}
aria-label="Hybrid inventory tabs"
>
<Tab
eventKey={0}
title={<TabTitleText>Conventional (RPM-DNF)</TabTitleText>}
>
{ConventionalInventoryTable}
</Tab>
<Tab
eventKey={1}
title={<TabTitleText>Immutable (OSTree)</TabTitleText>}
>
<ImmutableDevicesView
skeletonRowQuantity={15}
hasCheckbox={true}
isSystemsView={false}
selectedItems={setSelectedImmutableDevices}
/>
</Tab>
</Tabs>
) : (
ConventionalInventoryTable
)}
</Modal>
</>
)
Expand All @@ -180,6 +294,7 @@ AddSystemsToGroupModal.propTypes = {
reloadData: PropTypes.func,
groupId: PropTypes.string,
groupName: PropTypes.string,
edgeParityIsAllowed: PropTypes.bool,
};

export default AddSystemsToGroupModal;
30 changes: 30 additions & 0 deletions src/components/InventoryTabs/ImmutableDevices/EdgeDevicesView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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 ImmutableDevicesView = (props) => {
const dispatch = useDispatch();
const notificationProp = getNotificationProp(dispatch);
return (
<AsyncComponent
appName="edge"
module="./DevicesView"
ErrorComponent={<ErrorState />}
navigateProp={useNavigate}
locationProp={useLocation}
notificationProp={notificationProp}
pathPrefix={resolveRelPath('')}
urlName={manageEdgeInventoryUrlName}
{...props}
/>
);
};

export default ImmutableDevicesView;

0 comments on commit bf61d25

Please sign in to comment.