diff --git a/src/components/VmsList/TableView.js b/src/components/VmsList/TableView.js
index 707aed1f0..1a45de0b7 100644
--- a/src/components/VmsList/TableView.js
+++ b/src/components/VmsList/TableView.js
@@ -11,19 +11,51 @@ import {
Tr,
} from '@patternfly/react-table'
-import { toJS, translate } from '_/helpers'
+import { translate } from '_/helpers'
-import { saveEventFilters, setVmSort } from '_/actions'
-import { NAME, SortFields } from '_/utils'
+import { setVmSort } from '_/actions'
+import {
+ SortFields,
+ ICON,
+ POOL_INFO,
+ ACTIONS,
+ NAME,
+ OS,
+ STATUS,
+} from '_/utils'
+
+import {
+ TableVm,
+} from './Vm'
+import {
+ TablePool,
+} from './Pool'
const TableView = ({
msg,
locale,
- children: rows,
- columns,
+ vmsAndPools,
sort,
setSort,
}) => {
+ const columns = [
+ { id: ICON },
+ {
+ ...SortFields[NAME],
+ sort: true,
+ },
+ {
+ ...SortFields[STATUS],
+ sort: true,
+ },
+ { id: POOL_INFO },
+ {
+ ...SortFields[OS],
+ sort: true,
+ },
+ { id: ACTIONS },
+ ]
+
const activeSortIndex = columns.findIndex(({ id }) => id === sort.id)
const activeSortDirection = sort.isAsc ? 'asc' : 'desc'
@@ -42,7 +74,7 @@ const TableView = ({
})
return (
<>
- { rows?.length > 0 && (
+ { vmsAndPools?.length > 0 && (
- { rows}
+ { vmsAndPools.map(entity => (
+ entity.get('isVm')
+ ? (
+
+ )
+ : (
+
+ )
+ ))}
) }
@@ -71,15 +119,9 @@ const TableView = ({
}
TableView.propTypes = {
- columns: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string.isRequired,
- messageDescriptor: PropTypes.object,
- sort: PropTypes.bool,
- })).isRequired,
msg: PropTypes.object.isRequired,
locale: PropTypes.string.isRequired,
- children: PropTypes.array.isRequired,
+ vmsAndPools: PropTypes.array.isRequired,
sort: PropTypes.shape({
id: PropTypes.string.isRequired,
isAsc: PropTypes.bool,
@@ -88,13 +130,8 @@ TableView.propTypes = {
}
export default connect(
- ({ userMessages }, { vmId }) => ({
- events: toJS(userMessages.getIn(['events', vmId])),
- eventFilters: toJS(userMessages.getIn(['eventFilters'], {})),
- eventSort: toJS(userMessages.getIn(['eventSort'])),
- }),
+ null,
(dispatch) => ({
- clearAllFilters: () => dispatch(saveEventFilters({ filters: {} })),
setSort: (sort) => dispatch(setVmSort({ sort })),
})
)(withMsg(TableView))
diff --git a/src/components/VmsList/VmCardList.js b/src/components/VmsList/VmCardList.js
index 95de65c8d..20b66ab49 100644
--- a/src/components/VmsList/VmCardList.js
+++ b/src/components/VmsList/VmCardList.js
@@ -1,33 +1,14 @@
-import React, { useContext, useEffect } from 'react'
+import React from 'react'
import PropTypes from 'prop-types'
-import { connect } from 'react-redux'
-import { MsgContext } from '_/intl'
-import { getByPage } from '_/actions'
-import {
- filterVms,
- sortFunction,
- SortFields,
- ICON,
- POOL_INFO,
- ACTIONS,
- NAME,
- OS,
- STATUS,
-} from '_/utils'
-
-import useInfiniteScroll from '@closeio/use-infinite-scroll'
import {
CardVm,
- TableVm,
} from './Vm'
import {
CardPool,
- TablePool,
} from './Pool'
import style from './style.css'
import { Gallery, GalleryItem } from '@patternfly/react-core'
-import TableView from './TableView'
/**
* Use Patternfly 'Single Select Card View' pattern to show every VM and Pool
@@ -37,138 +18,21 @@ import TableView from './TableView'
* before this component is rendered. This will prevent two "initial page" fetches
* from running at the same time. The `VmsList` component handles this normally.
*/
-const VmCardList = ({ vms, alwaysShowPoolCard, fetchMoreVmsAndPools, tableView }) => {
- const { msg, locale } = useContext(MsgContext)
- const sort = vms.get('sort').toJS()
- const filters = vms.get('filters').toJS()
-
- // Filter the VMs (1. apply the filter bar criteria, 2. only show Pool VMs if the Pool exists)
- const filteredVms = vms.get('vms')
- .filter(vm => filterVms(vm, filters))
- .filter(vm => vm.getIn(['pool', 'id'], false) ? !!vms.getIn(['pools', vm.getIn(['pool', 'id'])], false) : true)
- .toList()
- .map(vm => vm.set('isVm', true))
-
- // Filter the Pools (only show a Pool card if the user can currently 'Take' a VM from it)
- const filteredPools = vms.get('pools')
- .filter(pool =>
- (alwaysShowPoolCard || (pool.get('vmsCount') < pool.get('maxUserVms') && pool.get('size') > 0)) &&
- filterVms(pool, filters)
- )
- .toList()
-
- // Display the VMs and Pools together, sorted nicely
- const vmsAndPools = [...filteredVms, ...filteredPools].sort(sortFunction(sort, locale, msg))
-
- // Handle the infinite scroll and pagination
- const hasMore = vms.get('vmsExpectMorePages') || vms.get('poolsExpectMorePages')
- const [page, sentinelRef, scrollerRef] = useInfiniteScroll({ hasMore, distance: 0 })
-
- useEffect(() => { // `VmsList` will not display this component until the first page of data is loaded
- if (page > 0) {
- fetchMoreVmsAndPools()
- }
- }, [page, fetchMoreVmsAndPools])
-
- useEffect(() => {
- if (!scrollerRef.current || !sentinelRef.current) {
- return
- }
-
- //
- // If a page fetch doesn't pull enough entities to push the sentinel out of view
- // underlying IntersectionObserver doesn't fire another event, and the scroller
- // gets stuck. Manually check if the sentinel is in view, and if it is, fetch
- // more data. The effect is only run when the `vms` part of the redux store is
- // updated.
- //
- const scrollRect = scrollerRef.current.getBoundingClientRect()
- const scrollVisibleTop = scrollRect.y
- const scrollVisibleBottom = scrollRect.y + scrollRect.height
-
- const sentinelRect = sentinelRef.current.getBoundingClientRect()
- const sentinelTop = sentinelRect.y
- const sentinelBottom = sentinelRect.y + sentinelRect.height
-
- const sentinelStillInView = sentinelBottom >= scrollVisibleTop && sentinelTop <= scrollVisibleBottom
- if (sentinelStillInView) {
- fetchMoreVmsAndPools()
- }
- }, [vms, scrollerRef, sentinelRef, fetchMoreVmsAndPools])
-
- const columnList = [
- { id: ICON },
- {
- ...SortFields[NAME],
- sort: true,
- },
- {
- ...SortFields[STATUS],
- sort: true,
- },
- { id: POOL_INFO },
- {
- ...SortFields[OS],
- sort: true,
- },
- { id: ACTIONS },
- ]
-
+const VmCardList = ({ vmsAndPools }) => {
return (
-
- { !tableView && (
-
- {vmsAndPools.map(entity => (
- {
+
+ {vmsAndPools.map(entity => (
+ {
entity.get('isVm')
?
: }
-
- ))}
-
- )}
- {tableView && (
-
- { vmsAndPools.map(entity => (
- entity.get('isVm')
- ? (
-
- )
- : (
-
- )
- ))}
-
- )}
- {hasMore && {msg.loadingTripleDot()}
}
-
+
+ ))}
+
)
}
VmCardList.propTypes = {
- tableView: PropTypes.bool.isRequired,
- vms: PropTypes.object.isRequired,
- alwaysShowPoolCard: PropTypes.bool,
- fetchMoreVmsAndPools: PropTypes.func.isRequired,
+ vmsAndPools: PropTypes.array.isRequired,
}
-export default connect(
- ({ vms, config, options }) => ({
- vms,
- alwaysShowPoolCard: !config.get('filter'),
- tableView: options.getIn(['remoteOptions', 'viewForVirtualMachines', 'content']) === 'table',
- }),
- (dispatch) => ({
- fetchMoreVmsAndPools: () => dispatch(getByPage()),
- })
-)(VmCardList)
+export default VmCardList
diff --git a/src/components/VmsList/index.js b/src/components/VmsList/index.js
index ac8e75ba0..dc7e45657 100644
--- a/src/components/VmsList/index.js
+++ b/src/components/VmsList/index.js
@@ -1,9 +1,17 @@
-import React, { useContext } from 'react'
+import React, { useContext, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
+import style from './style.css'
+import { getByPage } from '_/actions'
+import useInfiniteScroll from '@closeio/use-infinite-scroll'
+import {
+ filterVms,
+ sortFunction,
+} from '_/utils'
+
import {
EmptyState,
EmptyStateIcon,
@@ -11,8 +19,9 @@ import {
Title,
} from '@patternfly/react-core'
import VmCardList from './VmCardList'
-import { MsgContext } from '_/intl'
+import { MsgContext, withMsg } from '_/intl'
import { AddCircleOIcon } from '@patternfly/react-icons/dist/esm/icons'
+import TableView from './TableView'
/**
* Component displayed when VMs or Pools exist but the data is still loading.
@@ -38,33 +47,133 @@ const NoVmAvailable = () => {
)
}
-const VmsList = ({ vms, waitForFirstFetch }) => {
+const InfiniteScroller = ({ children, className, fetchMoreVmsAndPools, vms }) => {
+ const { msg } = useContext(MsgContext)
+ // Handle the infinite scroll and pagination
+ const hasMore = vms.get('vmsExpectMorePages') || vms.get('poolsExpectMorePages')
+ const [page, sentinelRef, scrollerRef] = useInfiniteScroll({ hasMore, distance: 0 })
+
+ useEffect(() => { // `VmsList` will not display this component until the first page of data is loaded
+ if (page > 0) {
+ fetchMoreVmsAndPools()
+ }
+ }, [page, fetchMoreVmsAndPools])
+
+ useEffect(() => {
+ if (!scrollerRef.current || !sentinelRef.current) {
+ return
+ }
+
+ //
+ // If a page fetch doesn't pull enough entities to push the sentinel out of view
+ // underlying IntersectionObserver doesn't fire another event, and the scroller
+ // gets stuck. Manually check if the sentinel is in view, and if it is, fetch
+ // more data. The effect is only run when the `vms` part of the redux store is
+ // updated.
+ //
+ const scrollRect = scrollerRef.current.getBoundingClientRect()
+ const scrollVisibleTop = scrollRect.y
+ const scrollVisibleBottom = scrollRect.y + scrollRect.height
+
+ const sentinelRect = sentinelRef.current.getBoundingClientRect()
+ const sentinelTop = sentinelRect.y
+ const sentinelBottom = sentinelRect.y + sentinelRect.height
+
+ const sentinelStillInView = sentinelBottom >= scrollVisibleTop && sentinelTop <= scrollVisibleBottom
+ if (sentinelStillInView) {
+ fetchMoreVmsAndPools()
+ }
+ }, [vms, scrollerRef, sentinelRef, fetchMoreVmsAndPools])
+
+ return (
+
+ {children}
+ {hasMore &&
{msg.loadingTripleDot()}
}
+
+ )
+}
+
+InfiniteScroller.propTypes = {
+ children: PropTypes.node,
+ className: PropTypes.string,
+ fetchMoreVmsAndPools: PropTypes.func.isRequired,
+ vms: PropTypes.object.isRequired,
+}
+
+const VmsList = ({
+ alwaysShowPoolCard,
+ fetchMoreVmsAndPools,
+ tableView,
+ vms,
+ waitForFirstFetch,
+ msg,
+ locale,
+}) => {
const haveVms = (vms.get('vms') && !vms.get('vms').isEmpty())
const havePools = (vms.get('pools') && !vms.get('pools').isEmpty())
- let el = null
-
if (waitForFirstFetch) {
- el =
- } else if (haveVms || havePools) {
- el =
- } else {
- el =
+ return
}
- return el
+ if (!haveVms && !havePools) {
+
+ }
+
+ const sort = vms.get('sort').toJS()
+ const filters = vms.get('filters').toJS()
+
+ // Filter the VMs (1. apply the filter bar criteria, 2. only show Pool VMs if the Pool exists)
+ const filteredVms = vms.get('vms')
+ .filter(vm => filterVms(vm, filters))
+ .filter(vm => vm.getIn(['pool', 'id'], false) ? !!vms.getIn(['pools', vm.getIn(['pool', 'id'])], false) : true)
+ .toList()
+ .map(vm => vm.set('isVm', true))
+
+ // Filter the Pools (only show a Pool card if the user can currently 'Take' a VM from it)
+ const filteredPools = vms.get('pools')
+ .filter(pool =>
+ (alwaysShowPoolCard || (pool.get('vmsCount') < pool.get('maxUserVms') && pool.get('size') > 0)) &&
+ filterVms(pool, filters)
+ )
+ .toList()
+
+ // Display the VMs and Pools together, sorted nicely
+ const vmsAndPools = [...filteredVms, ...filteredPools].sort(sortFunction(sort, locale, msg))
+
+ return (
+
+ {tableView && }
+ {!tableView && }
+
+ )
}
VmsList.propTypes = {
+ alwaysShowPoolCard: PropTypes.bool,
+ fetchMoreVmsAndPools: PropTypes.func.isRequired,
+ tableView: PropTypes.bool.isRequired,
vms: PropTypes.object.isRequired,
waitForFirstFetch: PropTypes.bool.isRequired,
+
+ msg: PropTypes.object.isRequired,
+ locale: PropTypes.string.isRequired,
}
export default withRouter(connect(
- (state) => ({
- vms: state.vms,
+ ({ vms, config, options }) => ({
+ vms,
+ alwaysShowPoolCard: !config.get('filter'),
+ tableView: options.getIn(['remoteOptions', 'viewForVirtualMachines', 'content']) === 'table',
waitForFirstFetch: (
- state.vms.get('vmsPage') === 0 && !!state.vms.get('vmsExpectMorePages') &&
- state.vms.get('poolsPage') === 0 && !!state.vms.get('poolsExpectMorePages')
+ vms.get('vmsPage') === 0 && !!vms.get('vmsExpectMorePages') &&
+ vms.get('poolsPage') === 0 && !!vms.get('poolsExpectMorePages')
),
+ }),
+ (dispatch) => ({
+ fetchMoreVmsAndPools: () => dispatch(getByPage()),
})
-)(VmsList))
+)(withMsg(VmsList)))
diff --git a/src/components/VmsList/style.css b/src/components/VmsList/style.css
index 0c8afed86..e6078ab53 100644
--- a/src/components/VmsList/style.css
+++ b/src/components/VmsList/style.css
@@ -51,8 +51,6 @@ td .vm-status {
margin-bottom: 0;
}
-
-
.vm-detail-link {
color: black;
}
@@ -153,4 +151,4 @@ dl.pool-info dd {
:global(#page-router-render-component) .tableView {
padding-top: 0;
-}
\ No newline at end of file
+}