From d34946ed52963cb285748ce9d9d208b3298eb1d0 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Tue, 14 Nov 2023 12:13:33 -0800 Subject: [PATCH 01/16] feat(THEEDGE-3703): fix condition to display tabs; remove federation; add update inline and button --- src/api/api.js | 6 + .../GroupSystems/GroupImmutableSystems.js | 270 ++++++++++++++++++ src/components/GroupSystems/GroupSystems.js | 2 +- src/components/GroupSystems/index.js | 13 +- .../InventoryGroupDetail/GroupTabDetails.js | 45 ++- 5 files changed, 328 insertions(+), 8 deletions(-) create mode 100644 src/components/GroupSystems/GroupImmutableSystems.js diff --git a/src/api/api.js b/src/api/api.js index bd5d86bc8..d7115b2f3 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -109,6 +109,7 @@ export const calculateSystemProfile = ({ osFilter, rhcdFilter, updateMethodFilter, + hostTypeFilter, }) => { let systemProfile = {}; const osFilterValues = Array.isArray(osFilter) @@ -159,6 +160,10 @@ export const calculateSystemProfile = ({ }; } + if (hostTypeFilter) { + systemProfile['host_type'] = hostTypeFilter; + } + return generateFilter({ system_profile: systemProfile }); }; @@ -172,6 +177,7 @@ export const filtersReducer = (acc, filter = {}) => ({ }), ...('osFilter' in filter && { osFilter: filter.osFilter }), ...('rhcdFilter' in filter && { rhcdFilter: filter.rhcdFilter }), + ...('hostTypeFilter' in filter && { hostTypeFilter: filter.hostTypeFilter }), ...('lastSeenFilter' in filter && { lastSeenFilter: filter.lastSeenFilter }), ...('updateMethodFilter' in filter && { updateMethodFilter: filter.updateMethodFilter, diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js new file mode 100644 index 000000000..69005145f --- /dev/null +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -0,0 +1,270 @@ +import { TableVariant, fitContent } from '@patternfly/react-table'; +import PropTypes from 'prop-types'; +import React, { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { selectEntity } from '../../store/inventory-actions'; +import AddSystemsToGroupModal from '../InventoryGroups/Modals/AddSystemsToGroupModal'; +import InventoryTable from '../InventoryTable/InventoryTable'; +import { Link, useNavigate } from 'react-router-dom'; +import RemoveHostsFromGroupModal from '../InventoryGroups/Modals/RemoveHostsFromGroupModal'; +import { usePermissionsWithContext } from '@redhat-cloud-services/frontend-components-utilities/RBACHook'; +import { + NO_MODIFY_GROUP_TOOLTIP_MESSAGE, + REQUIRED_PERMISSIONS_TO_MODIFY_GROUP, +} from '../../constants'; +import { + ActionButton, + ActionDropdownItem, +} from '../InventoryTable/ActionWithRBAC'; +import { clearEntitiesAction } from '../../store/actions'; +import { useBulkSelectConfig } from '../../Utilities/hooks/useBulkSelectConfig'; +import difference from 'lodash/difference'; +import map from 'lodash/map'; +export const prepareColumns = ( + initialColumns, + hideGroupColumn, + openTabOnClick = false +) => { + // hides the "groups" column + const columns = hideGroupColumn + ? initialColumns.filter(({ key }) => key !== 'groups') + : initialColumns; + + // additionally insert the "update method" column + columns.splice(columns.length - 2 /* must be the 3rd col from the end */, 0, { + key: 'update_method', + title: 'Update method', + sortKey: 'update_method', + transforms: [fitContent], + renderFunc: (value, hostId, systemData) => + systemData?.system_profile?.system_update_method || 'N/A', + props: { + // TODO: remove isStatic when the sorting is supported by API + isStatic: true, + width: 10, + }, + }); + + columns[columns.findIndex(({ key }) => key === 'display_name')].renderFunc = ( + value, + hostId + ) => ( +
+ + {value} + +
+ ); + + // map columns to the speicifc order + return [ + 'display_name', + 'groups', + 'tags', + 'system_profile', + 'update_method', + 'updated', + ] + .map((colKey) => columns.find(({ key }) => key === colKey)) + .filter(Boolean); // eliminate possible undefined's +}; + +const GroupImmutableSystems = ({ groupName, groupId }) => { + const dispatch = useDispatch(); + const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = + useState(false); + const [currentSystem, setCurrentSystem] = useState([]); + const inventory = useRef(null); + + const selected = useSelector( + (state) => state?.entities?.selected || new Map() + ); + const rows = useSelector(({ entities }) => entities?.rows || []); + const total = useSelector(({ entities }) => entities?.total); + const displayedIds = map(rows, 'id'); + const pageSelected = + difference(displayedIds, [...selected.keys()]).length === 0; + + const [addToGroupModalOpen, setAddToGroupModalOpen] = useState(false); + + const { hasAccess: canModify } = usePermissionsWithContext( + REQUIRED_PERMISSIONS_TO_MODIFY_GROUP(groupId) + ); + + useEffect(() => { + return () => { + dispatch(clearEntitiesAction()); + }; + }, []); + + const calculateSelected = () => (selected ? selected.size : 0); + + const bulkSelectConfig = useBulkSelectConfig( + selected, + null, + total, + rows, + true, + pageSelected, + groupName + ); + return ( +
+ {addToGroupModalOpen && ( + { + dispatch(clearEntitiesAction()); + setAddToGroupModalOpen(value); + }} + groupId={groupId} + groupName={groupName} + /> + )} + {removeHostsFromGroupModalOpen && ( + { + if (calculateSelected() > 0) { + dispatch(selectEntity(-1, false)); + } + + inventory.current.onRefreshData({}, false, true); + }} + /> + )} + {!addToGroupModalOpen && ( + prepareColumns(columns, true)} + hideFilters={{ hostGroupFilter: true }} + getEntities={async (items, config, showTags, defaultGetEntities) => + await defaultGetEntities( + items, + // filter systems by the group name + { + ...config, + filters: { + ...config.filters, + hostGroupFilter: [groupName], + hostTypeFilter: 'edge', + }, + }, + showTags + ) + } + tableProps={{ + isStickyHeader: true, + variant: TableVariant.compact, + canSelectAll: false, + actionResolver: (row) => [ + { + title: ( + { + setCurrentSystem([row]); + setRemoveHostsFromGroupModalOpen(true); + }} + > + Remove from group + + ), + style: { + padding: 0, // custom component creates extra padding space + }, + }, + { + title: ( + { + setCurrentSystem([row]); + useNavigate({ + pathname: `${location.pathname}/update`, + search: '?from_details=true', + }); + }} + > + Update + + ), + style: { + padding: 0, // custom component creates extra padding space + }, + }, + ], + }} + actionsConfig={{ + actions: [ + [ + { + dispatch(clearEntitiesAction()); + setAddToGroupModalOpen(true); + }} + ouiaId="add-systems-button" + > + Add systems + , + { + console.log('Call update'); + }} + ouiaId="update-systems-button" + > + Update + , + ], + { + label: 'Remove from group', + props: { + isAriaDisabled: !canModify || calculateSelected() === 0, + ...(!canModify && { + tooltip: NO_MODIFY_GROUP_TOOLTIP_MESSAGE, + }), + }, + onClick: () => { + setCurrentSystem(Array.from(selected.values())); + setRemoveHostsFromGroupModalOpen(true); + }, + }, + ], + }} + bulkSelect={bulkSelectConfig} + showTags + ref={inventory} + showCentosVersions + /> + )} +
+ ); +}; + +GroupImmutableSystems.propTypes = { + groupName: PropTypes.string.isRequired, + groupId: PropTypes.string.isRequired, +}; + +export default GroupImmutableSystems; diff --git a/src/components/GroupSystems/GroupSystems.js b/src/components/GroupSystems/GroupSystems.js index 556588e65..6e6280d29 100644 --- a/src/components/GroupSystems/GroupSystems.js +++ b/src/components/GroupSystems/GroupSystems.js @@ -20,7 +20,6 @@ import { clearEntitiesAction } from '../../store/actions'; import { useBulkSelectConfig } from '../../Utilities/hooks/useBulkSelectConfig'; import difference from 'lodash/difference'; import map from 'lodash/map'; - export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -230,6 +229,7 @@ const GroupSystems = ({ groupName, groupId }) => { GroupSystems.propTypes = { groupName: PropTypes.string.isRequired, groupId: PropTypes.string.isRequired, + hostType: PropTypes.string, }; export default GroupSystems; diff --git a/src/components/GroupSystems/index.js b/src/components/GroupSystems/index.js index 85887a3ff..eb20ff7a0 100644 --- a/src/components/GroupSystems/index.js +++ b/src/components/GroupSystems/index.js @@ -4,12 +4,12 @@ import React from 'react'; import { useSelector } from 'react-redux'; import NoSystemsEmptyState from '../InventoryGroupDetail/NoSystemsEmptyState'; import GroupSystems from './GroupSystems'; +import GroupImmutableSystems from './GroupImmutableSystems'; -const GroupSystemsWrapper = ({ groupName, groupId }) => { +const GroupSystemsWrapper = ({ groupName, groupId, hostType }) => { const { uninitialized, loading, data } = useSelector( (state) => state.groupDetail ); - return uninitialized || loading ? ( @@ -17,7 +17,11 @@ const GroupSystemsWrapper = ({ groupName, groupId }) => { ) : (data?.results?.[0]?.host_count || 0) > 0 ? ( - + hostType == 'immutable' ? ( + + ) : ( + + ) ) : ( ); @@ -26,7 +30,8 @@ const GroupSystemsWrapper = ({ groupName, groupId }) => { GroupSystemsWrapper.propTypes = { groupName: PropTypes.string.isRequired, groupId: PropTypes.string.isRequired, + hostType: PropTypes.string, }; export default GroupSystemsWrapper; -export { GroupSystems }; +export { GroupSystems, GroupImmutableSystems }; diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index 149f934ab..8532d63b0 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -9,10 +9,11 @@ import { import React, { Suspense, lazy, useState } from 'react'; import { hybridInventoryTabKeys } from '../../Utilities/constants'; import GroupSystems from '../GroupSystems'; +import GroupImmutableSystems from '../GroupSystems/GroupImmutableSystems'; 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 EdgeDeviceGroupiew from '../InventoryTabs/ImmutableDevices/EdgeDevicesGroupView'; import { EmptyStateNoAccessToSystems } from './EmptyStateNoAccess'; const GroupDetailInfo = lazy(() => import('./GroupDetailInfo')); @@ -24,12 +25,39 @@ const GroupTabDetailsWrapper = ({ hasEdgeImages, }) => { const [tab, setTab] = useState(0); + const { hasAccess: canViewHosts } = usePermissionsWithContext( REQUIRED_PERMISSIONS_TO_READ_GROUP_HOSTS(groupId) ); + const conventionalSystemsContent = ( + + ); + + const immutableSystemsContent = ( + + ); + + const [component, setComponent] = + activeTab == hybridInventoryTabKeys.conventional.key + ? useState(conventionalSystemsContent) + : useState(immutableSystemsContent); const handleTabClick = (_event, tabIndex) => { + setComponent(null); setTab(tabIndex); + if (tabIndex == hybridInventoryTabKeys.conventional.key) { + setComponent(conventionalSystemsContent); + } else { + setComponent(immutableSystemsContent); + } }; const [activeTabKey, setActiveTabKey] = useState(0); @@ -57,13 +85,24 @@ const GroupTabDetailsWrapper = ({ eventKey={hybridInventoryTabKeys.conventional.key} title={Conventional (RPM-DNF)} > - + {component} + {/* */} Immutable (OSTree)} > - + {component} + {/* */} + {/* */} ) : canViewHosts ? ( From 24abeed0b638ef5cc1aca0d84297fc129e3fbae1 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Wed, 15 Nov 2023 11:22:52 -0800 Subject: [PATCH 02/16] feat(THEEDGE-3703): add validation for inline update action --- .../GroupSystems/GroupImmutableSystems.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 69005145f..91362aa72 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -20,6 +20,7 @@ import { clearEntitiesAction } from '../../store/actions'; import { useBulkSelectConfig } from '../../Utilities/hooks/useBulkSelectConfig'; import difference from 'lodash/difference'; import map from 'lodash/map'; +import { useGetDevice } from '../../api/edge/imagesInfo'; export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -94,6 +95,29 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { REQUIRED_PERMISSIONS_TO_MODIFY_GROUP(groupId) ); + const getDevice = useGetDevice(); + const [deviceData, setDeviceData] = useState(null); + const [updateAvailable, setUpdateAvailable] = useState([]); + + // change to the new endpoint to avoid loop and performance issue + useEffect(() => { + const data = []; + rows.map((row) => { + const device = async () => await getDevice(row.id); + setDeviceData(device); + data.push({ + device_id: row.id, + update_available: + deviceData?.UpdateTransactions?.[0]?.Status === 'BUILDING' || + deviceData?.UpdateTransactions?.[0]?.Status === 'CREATED' || + !deviceData?.ImageInfo?.UpdatesAvailable?.length > 0, + }); + }); + setUpdateAvailable(data); + }, [rows]); + + console.log(updateAvailable); + useEffect(() => { return () => { dispatch(clearEntitiesAction()); @@ -185,11 +209,16 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { { title: ( obj.device_id === row.id) + ?.update_available + } requiredPermissions={REQUIRED_PERMISSIONS_TO_MODIFY_GROUP( groupId )} noAccessTooltip={NO_MODIFY_GROUP_TOOLTIP_MESSAGE} onClick={() => { + console.log(location.pathname); setCurrentSystem([row]); useNavigate({ pathname: `${location.pathname}/update`, @@ -204,6 +233,7 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { padding: 0, // custom component creates extra padding space }, }, + // {actionsEdge}, ], }} actionsConfig={{ From d2c155fdd281f5ccdbd6670ad61d1d2ac596c6bd Mon Sep 17 00:00:00 2001 From: acosferreia Date: Wed, 15 Nov 2023 13:17:25 -0800 Subject: [PATCH 03/16] feat(THEEDGE-3703): fix validation for inline update action --- .../GroupSystems/GroupImmutableSystems.js | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 91362aa72..3b76582f7 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -72,7 +72,7 @@ export const prepareColumns = ( .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's }; - +let data = []; const GroupImmutableSystems = ({ groupName, groupId }) => { const dispatch = useDispatch(); const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = @@ -96,27 +96,26 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { ); const getDevice = useGetDevice(); - const [deviceData, setDeviceData] = useState(null); - const [updateAvailable, setUpdateAvailable] = useState([]); + const [deviceData, setDeviceData] = useState(); // change to the new endpoint to avoid loop and performance issue useEffect(() => { - const data = []; rows.map((row) => { - const device = async () => await getDevice(row.id); - setDeviceData(device); - data.push({ - device_id: row.id, - update_available: - deviceData?.UpdateTransactions?.[0]?.Status === 'BUILDING' || - deviceData?.UpdateTransactions?.[0]?.Status === 'CREATED' || - !deviceData?.ImageInfo?.UpdatesAvailable?.length > 0, - }); + (async () => { + const device = await getDevice(row.id); + setDeviceData(device); + })(); }); - setUpdateAvailable(data); }, [rows]); - - console.log(updateAvailable); + useEffect(() => { + data.push({ + device_id: deviceData?.Device?.UUID, + update_available: + deviceData?.UpdateTransactions?.[0]?.Status === 'BUILDING' || + deviceData?.UpdateTransactions?.[0]?.Status === 'CREATED' || + !deviceData?.ImageInfo?.UpdatesAvailable?.length > 0, + }); + }, [deviceData]); useEffect(() => { return () => { @@ -210,7 +209,7 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { title: ( obj.device_id === row.id) + data.find((obj) => obj.device_id === row.id) ?.update_available } requiredPermissions={REQUIRED_PERMISSIONS_TO_MODIFY_GROUP( @@ -233,7 +232,6 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { padding: 0, // custom component creates extra padding space }, }, - // {actionsEdge}, ], }} actionsConfig={{ From c05fae2f5e4f74e87dac35fd7ff8e67e02447f96 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Wed, 15 Nov 2023 21:44:26 -0800 Subject: [PATCH 04/16] feat(THEEDGE-3703): change endpoint; fix update action to call update details --- src/api/edge/imagesInfo.js | 6 ++ .../GroupSystems/GroupImmutableSystems.js | 75 ++++++++++++------- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/api/edge/imagesInfo.js b/src/api/edge/imagesInfo.js index 41aab0d5e..90fcefa04 100644 --- a/src/api/edge/imagesInfo.js +++ b/src/api/edge/imagesInfo.js @@ -10,6 +10,12 @@ export const useGetDevice = () => { const axios = useAxiosWithPlatformInterceptors(); return (id) => axios.get(`${EDGE_API}/devices/${id}`); }; + +export const useGetInventoryGroupUpdateInfo = () => { + const axios = useAxiosWithPlatformInterceptors(); + return (id) => + axios.get(`${EDGE_API}/updates/inventory-groups/${id}/update-info`); +}; export const getTableParams = (param) => { if (param === undefined) { return ''; diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 3b76582f7..3fa65b942 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -20,7 +20,10 @@ import { clearEntitiesAction } from '../../store/actions'; import { useBulkSelectConfig } from '../../Utilities/hooks/useBulkSelectConfig'; import difference from 'lodash/difference'; import map from 'lodash/map'; -import { useGetDevice } from '../../api/edge/imagesInfo'; +import { + // useGetDevice, + useGetInventoryGroupUpdateInfo, +} from '../../api/edge/imagesInfo'; export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -73,7 +76,12 @@ export const prepareColumns = ( .filter(Boolean); // eliminate possible undefined's }; let data = []; + const GroupImmutableSystems = ({ groupName, groupId }) => { + const navigate = useNavigate(); + const canUpdateSelectedDevices = (deviceIds, imageSets) => + deviceIds?.length > 0 && imageSets?.length == 1 ? true : false; + const [deviceIds, setDeviceIds] = useState([]); const dispatch = useDispatch(); const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = useState(false); @@ -95,27 +103,16 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { REQUIRED_PERMISSIONS_TO_MODIFY_GROUP(groupId) ); - const getDevice = useGetDevice(); + // const getDevice = useGetDevice(); + const getUpdateInfo = useGetInventoryGroupUpdateInfo(); const [deviceData, setDeviceData] = useState(); - // change to the new endpoint to avoid loop and performance issue useEffect(() => { - rows.map((row) => { - (async () => { - const device = await getDevice(row.id); - setDeviceData(device); - })(); - }); + (async () => { + const updateInfo = await getUpdateInfo(groupId); + setDeviceData(updateInfo?.update_devices_uuids); + })(); }, [rows]); - useEffect(() => { - data.push({ - device_id: deviceData?.Device?.UUID, - update_available: - deviceData?.UpdateTransactions?.[0]?.Status === 'BUILDING' || - deviceData?.UpdateTransactions?.[0]?.Status === 'CREATED' || - !deviceData?.ImageInfo?.UpdatesAvailable?.length > 0, - }); - }, [deviceData]); useEffect(() => { return () => { @@ -125,6 +122,9 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const calculateSelected = () => (selected ? selected.size : 0); + //enable/disable update button + const [imageSet, setImageSet] = useState([]); + const bulkSelectConfig = useBulkSelectConfig( selected, null, @@ -134,6 +134,26 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { pageSelected, groupName ); + + //enable disable bulk update based on selection, must refactor + useEffect(() => { + if (selected.size > 0) { + setImageSet([]); + setDeviceIds([]); + return () => { + [...selected.keys()].map((s) => { + const img = data.find((obj) => obj.device_id === s)?.imageData; + + if (imageSet && !imageSet.includes(img)) { + setImageSet((imageSet) => [...imageSet, img]); + } + setDeviceIds((deviceIds) => [...deviceIds, s]); + }); + console.log(imageSet); + console.log(canUpdateSelectedDevices(deviceIds, imageSet)); + }; + } + }, [deviceData, selected]); return (
{addToGroupModalOpen && ( @@ -208,21 +228,19 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { { title: ( obj.device_id === row.id) - ?.update_available - } + isAriaDisabled={!deviceData.find((obj) => obj === row.id)} requiredPermissions={REQUIRED_PERMISSIONS_TO_MODIFY_GROUP( groupId )} noAccessTooltip={NO_MODIFY_GROUP_TOOLTIP_MESSAGE} onClick={() => { - console.log(location.pathname); setCurrentSystem([row]); - useNavigate({ - pathname: `${location.pathname}/update`, - search: '?from_details=true', - }); + navigate(`/insights/inventory/${row.id}/update`); + // useNavigate({ + // // pathname: `${location.pathname}/update`, + // pathname: `/insights/inventory/${row.id}/update`, + // search: '?from_details=true', + // }); }} > Update @@ -261,6 +279,9 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { console.log('Call update'); }} ouiaId="update-systems-button" + isAriaDisabled={ + !canUpdateSelectedDevices(deviceIds, imageSet) + } > Update , From 5b41138965806e6bad88b886eef4eeb73e73dcb9 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Fri, 17 Nov 2023 21:06:24 -0800 Subject: [PATCH 05/16] feat(THEEDGE-3703): include update button validation for enable disable --- .../GroupSystems/GroupImmutableSystems.js | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 3fa65b942..254ebf05a 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -75,13 +75,12 @@ export const prepareColumns = ( .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's }; -let data = []; const GroupImmutableSystems = ({ groupName, groupId }) => { const navigate = useNavigate(); const canUpdateSelectedDevices = (deviceIds, imageSets) => deviceIds?.length > 0 && imageSets?.length == 1 ? true : false; - const [deviceIds, setDeviceIds] = useState([]); + // const [deviceIds, setDeviceIds] = useState([]); const dispatch = useDispatch(); const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = useState(false); @@ -106,14 +105,15 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { // const getDevice = useGetDevice(); const getUpdateInfo = useGetInventoryGroupUpdateInfo(); const [deviceData, setDeviceData] = useState(); + const [deviceImageSet, setDeviceImageSet] = useState(); useEffect(() => { (async () => { const updateInfo = await getUpdateInfo(groupId); setDeviceData(updateInfo?.update_devices_uuids); + setDeviceImageSet(updateInfo?.device_image_set_info); })(); }, [rows]); - useEffect(() => { return () => { dispatch(clearEntitiesAction()); @@ -123,8 +123,10 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const calculateSelected = () => (selected ? selected.size : 0); //enable/disable update button - const [imageSet, setImageSet] = useState([]); - + // const [imageSet, setImageSet] = useState([]); + const [canUpdate, setCanUpdate] = useState(false); + let imageSet = []; + let deviceIds = []; const bulkSelectConfig = useBulkSelectConfig( selected, null, @@ -138,22 +140,24 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { //enable disable bulk update based on selection, must refactor useEffect(() => { if (selected.size > 0) { - setImageSet([]); - setDeviceIds([]); + // setImageSet([]); + // setDeviceIds([]); return () => { [...selected.keys()].map((s) => { - const img = data.find((obj) => obj.device_id === s)?.imageData; - - if (imageSet && !imageSet.includes(img)) { - setImageSet((imageSet) => [...imageSet, img]); + const img = deviceImageSet[s]; + if (!imageSet.includes(img)) { + // setImageSet((imageSet) => [...imageSet, img]); + imageSet.push(img); } - setDeviceIds((deviceIds) => [...deviceIds, s]); + // setDeviceIds((deviceIds) => [...deviceIds, s]); + deviceIds.push(s); }); - console.log(imageSet); - console.log(canUpdateSelectedDevices(deviceIds, imageSet)); + setCanUpdate(canUpdateSelectedDevices(deviceIds, imageSet)); }; } }, [deviceData, selected]); + // console.log(imageSet); + // console.log(canUpdateSelectedDevices(deviceIds, imageSet)); return (
{addToGroupModalOpen && ( @@ -279,9 +283,7 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { console.log('Call update'); }} ouiaId="update-systems-button" - isAriaDisabled={ - !canUpdateSelectedDevices(deviceIds, imageSet) - } + isAriaDisabled={!canUpdate} > Update , From 8b17f3f6a44f7faed85798d9e634b4c51a1ed7c5 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Mon, 20 Nov 2023 13:02:49 -0800 Subject: [PATCH 06/16] feat(THEEDGE-3703): call modal to update; add notification; --- .../GroupSystems/GroupImmutableSystems.js | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 254ebf05a..a81cf017b 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { selectEntity } from '../../store/inventory-actions'; import AddSystemsToGroupModal from '../InventoryGroups/Modals/AddSystemsToGroupModal'; import InventoryTable from '../InventoryTable/InventoryTable'; -import { Link, useNavigate } from 'react-router-dom'; +import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; import RemoveHostsFromGroupModal from '../InventoryGroups/Modals/RemoveHostsFromGroupModal'; import { usePermissionsWithContext } from '@redhat-cloud-services/frontend-components-utilities/RBACHook'; import { @@ -20,10 +20,10 @@ import { clearEntitiesAction } from '../../store/actions'; import { useBulkSelectConfig } from '../../Utilities/hooks/useBulkSelectConfig'; import difference from 'lodash/difference'; import map from 'lodash/map'; -import { - // useGetDevice, - useGetInventoryGroupUpdateInfo, -} from '../../api/edge/imagesInfo'; +import { useGetInventoryGroupUpdateInfo } from '../../api/edge/imagesInfo'; +import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent'; +import { getNotificationProp } from '../../Utilities/edge'; + export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -80,7 +80,6 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const navigate = useNavigate(); const canUpdateSelectedDevices = (deviceIds, imageSets) => deviceIds?.length > 0 && imageSets?.length == 1 ? true : false; - // const [deviceIds, setDeviceIds] = useState([]); const dispatch = useDispatch(); const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = useState(false); @@ -97,15 +96,21 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { difference(displayedIds, [...selected.keys()]).length === 0; const [addToGroupModalOpen, setAddToGroupModalOpen] = useState(false); - + const [updateDevice, setupdateDevice] = useState(false); const { hasAccess: canModify } = usePermissionsWithContext( REQUIRED_PERMISSIONS_TO_MODIFY_GROUP(groupId) ); - // const getDevice = useGetDevice(); const getUpdateInfo = useGetInventoryGroupUpdateInfo(); const [deviceData, setDeviceData] = useState(); const [deviceImageSet, setDeviceImageSet] = useState(); + const [updateModal, setUpdateModal] = useState({ + isOpen: false, + deviceData: null, + imageData: null, + }); + + const notificationProp = getNotificationProp(dispatch); useEffect(() => { (async () => { @@ -123,8 +128,19 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const calculateSelected = () => (selected ? selected.size : 0); //enable/disable update button - // const [imageSet, setImageSet] = useState([]); const [canUpdate, setCanUpdate] = useState(false); + const [updateImageSet, setUpdateImageSet] = useState(); + const handleUpdateSelected = () => { + setUpdateModal((prevState) => ({ + ...prevState, + deviceData: [...selected.keys()].map((device) => ({ + id: device, + })), + imageSetId: updateImageSet, + isOpen: true, + })); + }; + let imageSet = []; let deviceIds = []; const bulkSelectConfig = useBulkSelectConfig( @@ -140,24 +156,19 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { //enable disable bulk update based on selection, must refactor useEffect(() => { if (selected.size > 0) { - // setImageSet([]); - // setDeviceIds([]); return () => { [...selected.keys()].map((s) => { const img = deviceImageSet[s]; if (!imageSet.includes(img)) { - // setImageSet((imageSet) => [...imageSet, img]); imageSet.push(img); } - // setDeviceIds((deviceIds) => [...deviceIds, s]); deviceIds.push(s); }); setCanUpdate(canUpdateSelectedDevices(deviceIds, imageSet)); + setUpdateImageSet(imageSet); }; } }, [deviceData, selected]); - // console.log(imageSet); - // console.log(canUpdateSelectedDevices(deviceIds, imageSet)); return (
{addToGroupModalOpen && ( @@ -186,6 +197,19 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { }} /> )} + {updateDevice && ( + true} + /> + )} {!addToGroupModalOpen && ( prepareColumns(columns, true)} @@ -240,11 +264,6 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { onClick={() => { setCurrentSystem([row]); navigate(`/insights/inventory/${row.id}/update`); - // useNavigate({ - // // pathname: `${location.pathname}/update`, - // pathname: `/insights/inventory/${row.id}/update`, - // search: '?from_details=true', - // }); }} > Update @@ -280,7 +299,8 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { noAccessTooltip={NO_MODIFY_GROUP_TOOLTIP_MESSAGE} key="update-systems-button" onClick={() => { - console.log('Call update'); + setupdateDevice(true); + handleUpdateSelected(); }} ouiaId="update-systems-button" isAriaDisabled={!canUpdate} From 93f4a97ff9ed1617a2dc7363ba2700706bff1f0c Mon Sep 17 00:00:00 2001 From: acosferreia Date: Mon, 20 Nov 2023 14:43:51 -0800 Subject: [PATCH 07/16] feat(THEEDGE-3703): fix tab init; --- .../GroupSystems/GroupImmutableSystems.js | 5 ++++- .../InventoryGroupDetail/GroupTabDetails.js | 14 +++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index a81cf017b..62d47da9d 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -71,6 +71,7 @@ export const prepareColumns = ( 'system_profile', 'update_method', 'updated', + 'Status', ] .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's @@ -256,7 +257,9 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { { title: ( obj === row.id)} + isAriaDisabled={ + deviceData && !deviceData.find((obj) => obj === row.id) + } requiredPermissions={REQUIRED_PERMISSIONS_TO_MODIFY_GROUP( groupId )} diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index 8532d63b0..996c42990 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -6,7 +6,7 @@ import { TabTitleText, Tabs, } from '@patternfly/react-core'; -import React, { Suspense, lazy, useState } from 'react'; +import React, { Suspense, lazy, useEffect, useState } from 'react'; import { hybridInventoryTabKeys } from '../../Utilities/constants'; import GroupSystems from '../GroupSystems'; import GroupImmutableSystems from '../GroupSystems/GroupImmutableSystems'; @@ -50,6 +50,18 @@ const GroupTabDetailsWrapper = ({ ? useState(conventionalSystemsContent) : useState(immutableSystemsContent); + useEffect( + () => { + setComponent(null); + if (activeTab == hybridInventoryTabKeys.conventional.key) { + setComponent(conventionalSystemsContent); + } else { + setComponent(immutableSystemsContent); + } + }, + [activeTab] + // ); + ); const handleTabClick = (_event, tabIndex) => { setComponent(null); setTab(tabIndex); From 4805c78b3f8caf6064a596ed5eacd8230c912dc1 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Mon, 20 Nov 2023 23:54:31 -0800 Subject: [PATCH 08/16] feat(THEEDGE-3703): add missing columns; --- .../GroupSystems/GroupImmutableSystems.js | 17 +++++++++++----- .../ImmutableDevices/ImmutableDevices.js | 1 - .../InventoryGroupDetail/GroupTabDetails.js | 20 ++++++++----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 62d47da9d..b17f99dc0 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -23,7 +23,7 @@ import map from 'lodash/map'; import { useGetInventoryGroupUpdateInfo } from '../../api/edge/imagesInfo'; import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent'; import { getNotificationProp } from '../../Utilities/edge'; - +import { edgeColumns } from '../ImmutableDevices/columns'; export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -48,7 +48,6 @@ export const prepareColumns = ( width: 10, }, }); - columns[columns.findIndex(({ key }) => key === 'display_name')].renderFunc = ( value, hostId @@ -71,17 +70,25 @@ export const prepareColumns = ( 'system_profile', 'update_method', 'updated', - 'Status', + // 'status' ] .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's }; const GroupImmutableSystems = ({ groupName, groupId }) => { + const dispatch = useDispatch(); + + const mergeColumns = (inventoryColumns) => { + const filteredColumns = inventoryColumns.filter( + (column) => column.key !== 'groups' + ); + return [...filteredColumns, ...edgeColumns]; + }; + const navigate = useNavigate(); const canUpdateSelectedDevices = (deviceIds, imageSets) => deviceIds?.length > 0 && imageSets?.length == 1 ? true : false; - const dispatch = useDispatch(); const [removeHostsFromGroupModalOpen, setRemoveHostsFromGroupModalOpen] = useState(false); const [currentSystem, setCurrentSystem] = useState([]); @@ -213,7 +220,7 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { )} {!addToGroupModalOpen && ( prepareColumns(columns, true)} + columns={(columns) => mergeColumns(columns)} hideFilters={{ hostGroupFilter: true }} getEntities={async (items, config, showTags, defaultGetEntities) => await defaultGetEntities( diff --git a/src/components/ImmutableDevices/ImmutableDevices.js b/src/components/ImmutableDevices/ImmutableDevices.js index 928c91e15..584eb7860 100644 --- a/src/components/ImmutableDevices/ImmutableDevices.js +++ b/src/components/ImmutableDevices/ImmutableDevices.js @@ -40,7 +40,6 @@ const ImmutableDevices = ({ const filteredColumns = inventoryColumns.filter( (column) => !column.inventoryGroupsFeatureFlag || inventoryGroupsEnabled ); - return [...mergeAppColumns(filteredColumns), ...edgeColumns]; }; diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index 996c42990..82393884a 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -50,18 +50,14 @@ const GroupTabDetailsWrapper = ({ ? useState(conventionalSystemsContent) : useState(immutableSystemsContent); - useEffect( - () => { - setComponent(null); - if (activeTab == hybridInventoryTabKeys.conventional.key) { - setComponent(conventionalSystemsContent); - } else { - setComponent(immutableSystemsContent); - } - }, - [activeTab] - // ); - ); + useEffect(() => { + setComponent(null); + if (activeTab == hybridInventoryTabKeys.conventional.key) { + setComponent(conventionalSystemsContent); + } else { + setComponent(immutableSystemsContent); + } + }, [activeTab]); const handleTabClick = (_event, tabIndex) => { setComponent(null); setTab(tabIndex); From 605c01ad3dceb0fceea5a29c951e6fd455bd14ac Mon Sep 17 00:00:00 2001 From: acosferreia Date: Tue, 21 Nov 2023 22:15:13 -0800 Subject: [PATCH 09/16] feat(THEEDGE-3703): add values and link to edge columns; --- src/api/api.js | 21 ++++-- .../GroupSystems/GroupImmutableSystems.js | 70 ++++++++++++------- src/components/ImmutableDevices/columns.js | 1 - .../InventoryGroupDetail/GroupTabDetails.js | 11 --- 4 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index d7115b2f3..1f14a89cf 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -321,11 +321,15 @@ export async function getEntities( .then(({ results = [], ...data } = {}) => ({ ...data, filters, - results: results.map((result) => - mapData({ - ...result, - display_name: result.display_name || result.fqdn || result.id, - }) + results: results.map( + (result) => + mapData({ + ...result, + display_name: result.display_name || result.fqdn || result.id, + // ImageSetId:1, + // ImageName: "cab" + }) + // fetchImagesData ), })); } @@ -405,3 +409,10 @@ export const fetchEdgeSystem = () => { console.log(err); } }; + +export const useGetImageData = () => { + // const axios = useAxiosWithPlatformInterceptors(); + return (deviceIDs) => { + return instance.post(`${EDGE_API_BASE}/devices/devicesview`, deviceIDs); + }; +}; diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index b17f99dc0..a15a66e04 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -24,6 +24,8 @@ import { useGetInventoryGroupUpdateInfo } from '../../api/edge/imagesInfo'; import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent'; import { getNotificationProp } from '../../Utilities/edge'; import { edgeColumns } from '../ImmutableDevices/columns'; +import { useGetImageData } from '../../api'; +import { mergeArraysByKey } from '@redhat-cloud-services/frontend-components-utilities/helpers'; export const prepareColumns = ( initialColumns, hideGroupColumn, @@ -70,15 +72,17 @@ export const prepareColumns = ( 'system_profile', 'update_method', 'updated', + 'ImageName', + 'imageName', // 'status' ] .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's }; -const GroupImmutableSystems = ({ groupName, groupId }) => { +const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { const dispatch = useDispatch(); - + const fetchImagesData = useGetImageData(); const mergeColumns = (inventoryColumns) => { const filteredColumns = inventoryColumns.filter( (column) => column.key !== 'groups' @@ -97,7 +101,9 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const selected = useSelector( (state) => state?.entities?.selected || new Map() ); - const rows = useSelector(({ entities }) => entities?.rows || []); + + let rows = useSelector(({ entities }) => entities?.rows || []); + const total = useSelector(({ entities }) => entities?.total); const displayedIds = map(rows, 'id'); const pageSelected = @@ -120,13 +126,39 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { const notificationProp = getNotificationProp(dispatch); - useEffect(() => { - (async () => { - const updateInfo = await getUpdateInfo(groupId); - setDeviceData(updateInfo?.update_devices_uuids); - setDeviceImageSet(updateInfo?.device_image_set_info); - })(); - }, [rows]); + const customGetEntities = async ( + _items, + config, + showTags, + defaultGetEntities + ) => { + const updateInfo = await getUpdateInfo(groupId); + setDeviceData(updateInfo?.update_devices_uuids); + setDeviceImageSet(updateInfo?.device_image_set_info); + const mapDeviceIds = Object.keys(updateInfo?.device_image_set_info); + const customResult = await fetchImagesData({ devices_uuid: mapDeviceIds }); + + //##################################// + const rowInfo = []; + customResult?.data?.devices.forEach((row) => { + rowInfo.push({ ...row, id: row.DeviceUUID }); + }); + //##################################// + const items = rowInfo.map(({ id }) => id); + const enhancedConfig = { ...config, hasItems: true }; // hasItems have to be set to true + + const defaultData = await defaultGetEntities( + items, + enhancedConfig, + showTags + ); // get default data for your items from inventory API + + return { + results: mergeArraysByKey([defaultData.results, rowInfo]), // merge common data and your data based on their ids (you can also use your own solution) + total: customResult.total, + }; + }; + useEffect(() => { return () => { dispatch(clearEntitiesAction()); @@ -222,21 +254,8 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { mergeColumns(columns)} hideFilters={{ hostGroupFilter: true }} - getEntities={async (items, config, showTags, defaultGetEntities) => - await defaultGetEntities( - items, - // filter systems by the group name - { - ...config, - filters: { - ...config.filters, - hostGroupFilter: [groupName], - hostTypeFilter: 'edge', - }, - }, - showTags - ) - } + // getEntities={entities} + getEntities={customGetEntities} tableProps={{ isStickyHeader: true, variant: TableVariant.compact, @@ -337,6 +356,7 @@ const GroupImmutableSystems = ({ groupName, groupId }) => { showTags ref={inventory} showCentosVersions + {...props} /> )}
diff --git a/src/components/ImmutableDevices/columns.js b/src/components/ImmutableDevices/columns.js index 0b10c6d79..16b340de1 100644 --- a/src/components/ImmutableDevices/columns.js +++ b/src/components/ImmutableDevices/columns.js @@ -36,7 +36,6 @@ export const edgeColumns = [ UpdateAvailable, DispatcherStatus ); - return deviceStatus === 'error' || deviceStatus === 'unresponsive' ? ( Conventional (RPM-DNF)} > {component} - {/* */} Immutable (OSTree)} > {component} - {/* */} - {/* */} ) : canViewHosts ? ( From fb07db482b0a7df888dc81c2283cc76c8bdb4460 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Tue, 21 Nov 2023 22:20:48 -0800 Subject: [PATCH 10/16] feat(THEEDGE-3703): clean up; --- src/api/api.js | 15 +++++---------- .../GroupSystems/GroupImmutableSystems.js | 3 --- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index 1f14a89cf..66919d8c8 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -321,15 +321,11 @@ export async function getEntities( .then(({ results = [], ...data } = {}) => ({ ...data, filters, - results: results.map( - (result) => - mapData({ - ...result, - display_name: result.display_name || result.fqdn || result.id, - // ImageSetId:1, - // ImageName: "cab" - }) - // fetchImagesData + results: results.map((result) => + mapData({ + ...result, + display_name: result.display_name || result.fqdn || result.id, + }) ), })); } @@ -411,7 +407,6 @@ export const fetchEdgeSystem = () => { }; export const useGetImageData = () => { - // const axios = useAxiosWithPlatformInterceptors(); return (deviceIDs) => { return instance.post(`${EDGE_API_BASE}/devices/devicesview`, deviceIDs); }; diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index a15a66e04..44f80af27 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -72,9 +72,6 @@ export const prepareColumns = ( 'system_profile', 'update_method', 'updated', - 'ImageName', - 'imageName', - // 'status' ] .map((colKey) => columns.find(({ key }) => key === colKey)) .filter(Boolean); // eliminate possible undefined's From 5688daa34bbb8f39a2e5102c9b72f48d72a86b38 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Tue, 21 Nov 2023 22:26:48 -0800 Subject: [PATCH 11/16] feat(THEEDGE-3703): fix total count; --- src/components/GroupSystems/GroupImmutableSystems.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 44f80af27..a9d242e36 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -134,7 +134,6 @@ const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { setDeviceImageSet(updateInfo?.device_image_set_info); const mapDeviceIds = Object.keys(updateInfo?.device_image_set_info); const customResult = await fetchImagesData({ devices_uuid: mapDeviceIds }); - //##################################// const rowInfo = []; customResult?.data?.devices.forEach((row) => { @@ -152,7 +151,7 @@ const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { return { results: mergeArraysByKey([defaultData.results, rowInfo]), // merge common data and your data based on their ids (you can also use your own solution) - total: customResult.total, + total: customResult?.data?.total, }; }; From a483d541723df760d4aa12035d692e7461ba85ab Mon Sep 17 00:00:00 2001 From: acosferreia Date: Wed, 22 Nov 2023 10:16:56 -0800 Subject: [PATCH 12/16] feat(THEEDGE-3703): remove conditional from hooks --- src/components/InventoryGroupDetail/GroupTabDetails.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index fd39194fd..bc16c5281 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -45,10 +45,7 @@ const GroupTabDetailsWrapper = ({ /> ); - const [component, setComponent] = - activeTab == hybridInventoryTabKeys.conventional.key - ? useState(conventionalSystemsContent) - : useState(immutableSystemsContent); + const [component, setComponent] = useState(conventionalSystemsContent); useEffect(() => { setComponent(null); From d75d2188151a45dfa10bb2fac07e0760515fcee3 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Thu, 23 Nov 2023 07:34:08 -0800 Subject: [PATCH 13/16] feat(THEEDGE-3703): clean up; pr fixes --- src/components/GroupSystems/GroupImmutableSystems.js | 10 +++------- src/components/GroupSystems/index.js | 2 +- src/components/InventoryGroupDetail/GroupTabDetails.js | 3 +-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index a9d242e36..13ea05089 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -134,23 +134,19 @@ const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { setDeviceImageSet(updateInfo?.device_image_set_info); const mapDeviceIds = Object.keys(updateInfo?.device_image_set_info); const customResult = await fetchImagesData({ devices_uuid: mapDeviceIds }); - //##################################// const rowInfo = []; customResult?.data?.devices.forEach((row) => { rowInfo.push({ ...row, id: row.DeviceUUID }); }); - //##################################// const items = rowInfo.map(({ id }) => id); - const enhancedConfig = { ...config, hasItems: true }; // hasItems have to be set to true - + const enhancedConfig = { ...config, hasItems: true }; const defaultData = await defaultGetEntities( items, enhancedConfig, showTags - ); // get default data for your items from inventory API - + ); return { - results: mergeArraysByKey([defaultData.results, rowInfo]), // merge common data and your data based on their ids (you can also use your own solution) + results: mergeArraysByKey([defaultData.results, rowInfo]), total: customResult?.data?.total, }; }; diff --git a/src/components/GroupSystems/index.js b/src/components/GroupSystems/index.js index eb20ff7a0..9a4311667 100644 --- a/src/components/GroupSystems/index.js +++ b/src/components/GroupSystems/index.js @@ -17,7 +17,7 @@ const GroupSystemsWrapper = ({ groupName, groupId, hostType }) => { ) : (data?.results?.[0]?.host_count || 0) > 0 ? ( - hostType == 'immutable' ? ( + hostType === 'immutable' ? ( ) : ( diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index bc16c5281..6414717b2 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -8,12 +8,11 @@ import { } from '@patternfly/react-core'; import React, { Suspense, lazy, useEffect, useState } from 'react'; import { hybridInventoryTabKeys } from '../../Utilities/constants'; -import GroupSystems from '../GroupSystems'; +import GroupSystems from '../GroupSystems/GroupSystems'; import GroupImmutableSystems from '../GroupSystems/GroupImmutableSystems'; 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')); From 9636d8d33ce40b9a1958d0d28bf13d702b1cd275 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Thu, 23 Nov 2023 08:07:46 -0800 Subject: [PATCH 14/16] feat(THEEDGE-3703): add usememo; remove code duplication; --- .../InventoryGroupDetail/GroupTabDetails.js | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/components/InventoryGroupDetail/GroupTabDetails.js b/src/components/InventoryGroupDetail/GroupTabDetails.js index 6414717b2..55e1a9c40 100644 --- a/src/components/InventoryGroupDetail/GroupTabDetails.js +++ b/src/components/InventoryGroupDetail/GroupTabDetails.js @@ -6,7 +6,7 @@ import { TabTitleText, Tabs, } from '@patternfly/react-core'; -import React, { Suspense, lazy, useEffect, useState } from 'react'; +import React, { Suspense, lazy, useEffect, useMemo, useState } from 'react'; import { hybridInventoryTabKeys } from '../../Utilities/constants'; import GroupSystems from '../GroupSystems/GroupSystems'; import GroupImmutableSystems from '../GroupSystems/GroupImmutableSystems'; @@ -28,36 +28,40 @@ const GroupTabDetailsWrapper = ({ const { hasAccess: canViewHosts } = usePermissionsWithContext( REQUIRED_PERMISSIONS_TO_READ_GROUP_HOSTS(groupId) ); - const conventionalSystemsContent = ( - + const conventionalSystemsContent = useMemo( + () => ( + + ), + [groupId, groupName] ); - const immutableSystemsContent = ( - + const immutableSystemsContent = useMemo( + () => ( + + ), + [groupId, groupName] ); const [component, setComponent] = useState(conventionalSystemsContent); useEffect(() => { - setComponent(null); - if (activeTab == hybridInventoryTabKeys.conventional.key) { + if (activeTab === hybridInventoryTabKeys.conventional.key) { setComponent(conventionalSystemsContent); } else { setComponent(immutableSystemsContent); } }, [activeTab]); const handleTabClick = (_event, tabIndex) => { - setComponent(null); setTab(tabIndex); - if (tabIndex == hybridInventoryTabKeys.conventional.key) { + if (tabIndex === hybridInventoryTabKeys.conventional.key) { setComponent(conventionalSystemsContent); } else { setComponent(immutableSystemsContent); From 6f9f918a76bd66889a9dcab1287870dee8f411f2 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Thu, 23 Nov 2023 10:05:20 -0800 Subject: [PATCH 15/16] feat(THEEDGE-3703): fix padding for buttons --- .../GroupSystems/GroupImmutableSystems.js | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 13ea05089..31baf5a69 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -299,35 +299,37 @@ const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { actionsConfig={{ actions: [ [ - { - dispatch(clearEntitiesAction()); - setAddToGroupModalOpen(true); - }} - ouiaId="add-systems-button" - > - Add systems - , - { - setupdateDevice(true); - handleUpdateSelected(); - }} - ouiaId="update-systems-button" - isAriaDisabled={!canUpdate} - > - Update - , +
+ { + dispatch(clearEntitiesAction()); + setAddToGroupModalOpen(true); + }} + ouiaId="add-systems-button" + > + Add systems + + { + setupdateDevice(true); + handleUpdateSelected(); + }} + ouiaId="update-systems-button" + isAriaDisabled={!canUpdate} + > + Update + +
, ], { label: 'Remove from group', From c6a8adfa4370ffd698eafc0e02deae07057a95e8 Mon Sep 17 00:00:00 2001 From: acosferreia Date: Thu, 23 Nov 2023 10:15:40 -0800 Subject: [PATCH 16/16] feat(THEEDGE-3703): enable select all --- src/components/GroupSystems/GroupImmutableSystems.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/GroupSystems/GroupImmutableSystems.js b/src/components/GroupSystems/GroupImmutableSystems.js index 31baf5a69..8a145b003 100644 --- a/src/components/GroupSystems/GroupImmutableSystems.js +++ b/src/components/GroupSystems/GroupImmutableSystems.js @@ -251,7 +251,7 @@ const GroupImmutableSystems = ({ groupName, groupId, ...props }) => { tableProps={{ isStickyHeader: true, variant: TableVariant.compact, - canSelectAll: false, + canSelectAll: true, actionResolver: (row) => [ { title: (