-
Notifications
You must be signed in to change notification settings - Fork 991
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #36822 - Design new hosts page
Update the TableIndexPage as a part of this action to accept things like select all Refs #36822 - Added a new change concent source action
- Loading branch information
Showing
13 changed files
with
752 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
webpack/assets/javascripts/react_app/components/HostsIndex/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react'; | ||
import { CubeIcon } from '@patternfly/react-icons'; | ||
import { translate as __ } from '../../common/I18n'; | ||
import TableIndexPage from '../PF4/TableIndexPage/TableIndexPage'; | ||
import { HOSTS_API_PATH, API_REQUEST_KEY } from '../../routes/Hosts/constants'; | ||
|
||
const HostsIndex = () => { | ||
const columns = { | ||
name: { | ||
title: __('Name'), | ||
wrapper: ({ can_edit: canEdit, id, name }) => | ||
canEdit ? ( | ||
<a href={`/models/${id}/edit`}>{name}</a> | ||
) : ( | ||
<span>{name}</span> | ||
), | ||
isSorted: true, | ||
}, | ||
}; | ||
|
||
const computeContentSource = search => | ||
`/change_host_content_source?search=${search}`; | ||
|
||
const customActionKebabs = [ | ||
{ | ||
title: __('Change content source'), | ||
icon: <CubeIcon />, | ||
computeHref: computeContentSource, | ||
}, | ||
]; | ||
|
||
return ( | ||
<TableIndexPage | ||
apiUrl={HOSTS_API_PATH} | ||
apiOptions={{ key: API_REQUEST_KEY }} | ||
header={__('Hosts')} | ||
controller="hosts" | ||
isDeleteable | ||
columns={columns} | ||
displaySelectAllCheckbox | ||
customActionKebabs={customActionKebabs} | ||
creatable={false} | ||
/> | ||
); | ||
}; | ||
|
||
export default HostsIndex; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
webpack/assets/javascripts/react_app/components/PF4/TableIndexPage/ActionKebab.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Dropdown, KebabToggle, DropdownItem } from '@patternfly/react-core'; | ||
|
||
/** | ||
* Generate a button or a dropdown of buttons | ||
* @param {String} title The title of the button for the title and text inside the button | ||
* @param {Object} action action to preform when the button is click can be href with data-method or Onclick | ||
* @return {Function} button component or splitbutton component | ||
*/ | ||
export const ActionKebab = ({ items: originalItems }) => { | ||
const items = [...originalItems]; | ||
const [isOpen, setIsOpen] = useState(false); | ||
if (!items.length) return null; | ||
return ( | ||
<> | ||
{items.length > 0 && ( | ||
<Dropdown | ||
ouiaId="action-buttons-dropdown" | ||
toggle={ | ||
<KebabToggle | ||
aria-label="toggle action dropdown" | ||
onToggle={setIsOpen} | ||
/> | ||
} | ||
isOpen={isOpen} | ||
isPlain | ||
dropdownItems={items.map(item => ( | ||
<DropdownItem | ||
ouiaId={`${item.title}-dropdown-item`} | ||
key={item.title} | ||
title={item.title} | ||
{...item.action} | ||
isDisabled={item.isDisabled} | ||
> | ||
{item.icon} {item.title} | ||
</DropdownItem> | ||
))} | ||
/> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
ActionKebab.propTypes = { | ||
items: PropTypes.arrayOf( | ||
PropTypes.shape({ | ||
action: PropTypes.object, | ||
title: PropTypes.string, | ||
icon: PropTypes.node, | ||
isDisabled: PropTypes.bool, | ||
}) | ||
), | ||
}; | ||
|
||
ActionKebab.defaultProps = { | ||
items: [], | ||
}; |
156 changes: 156 additions & 0 deletions
156
...ack/assets/javascripts/react_app/components/PF4/TableIndexPage/Table/SelectAllCheckbox.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { | ||
Dropdown, | ||
DropdownToggle, | ||
DropdownToggleCheckbox, | ||
DropdownItem, | ||
} from '@patternfly/react-core'; | ||
import { translate as __ } from '../../../../common/I18n'; | ||
import { noop } from '../../../../common/helpers'; | ||
|
||
import './SelectAllCheckbox.scss'; | ||
|
||
const SelectAllCheckbox = ({ | ||
selectNone, | ||
selectPage, | ||
selectedCount, | ||
pageRowCount, | ||
totalCount, | ||
areAllRowsOnPageSelected, | ||
areAllRowsSelected, | ||
selectAll, | ||
}) => { | ||
const [isSelectAllDropdownOpen, setSelectAllDropdownOpen] = useState(false); | ||
const [selectionToggle, setSelectionToggle] = useState(false); | ||
|
||
const canSelectAll = selectAll !== noop; | ||
// Checkbox states: false = unchecked, null = partially-checked, true = checked | ||
// Flow: All are selected -> click -> none are selected | ||
// Some are selected -> click -> none are selected | ||
// None are selected -> click -> page is selected | ||
const onSelectAllCheckboxChange = checked => { | ||
if (checked && selectionToggle !== null) { | ||
if (!canSelectAll) { | ||
selectPage(); | ||
} else { | ||
selectAll(true); | ||
} | ||
} else { | ||
selectNone(); | ||
} | ||
}; | ||
|
||
const onSelectAllDropdownToggle = () => | ||
setSelectAllDropdownOpen(isOpen => !isOpen); | ||
|
||
const handleSelectAll = () => { | ||
setSelectAllDropdownOpen(false); | ||
setSelectionToggle(true); | ||
selectAll(true); | ||
}; | ||
const handleSelectPage = () => { | ||
setSelectAllDropdownOpen(false); | ||
setSelectionToggle(true); | ||
selectPage(); | ||
}; | ||
const handleSelectNone = () => { | ||
setSelectAllDropdownOpen(false); | ||
setSelectionToggle(false); | ||
selectNone(); | ||
}; | ||
|
||
useEffect(() => { | ||
let newCheckedState = null; // null is partially-checked state | ||
|
||
if (areAllRowsSelected) { | ||
newCheckedState = true; | ||
} else if (selectedCount === 0) { | ||
newCheckedState = false; | ||
} | ||
setSelectionToggle(newCheckedState); | ||
}, [selectedCount, areAllRowsSelected]); | ||
|
||
const selectAllDropdownItems = [ | ||
<DropdownItem | ||
key="select-none" | ||
ouiaId="select-none" | ||
component="button" | ||
isDisabled={selectedCount === 0} | ||
onClick={handleSelectNone} | ||
> | ||
{`${__('Select none')} (0)`} | ||
</DropdownItem>, | ||
<DropdownItem | ||
key="select-page" | ||
ouiaId="select-page" | ||
component="button" | ||
isDisabled={pageRowCount === 0 || areAllRowsOnPageSelected} | ||
onClick={handleSelectPage} | ||
> | ||
{`${__('Select page')} (${pageRowCount})`} | ||
</DropdownItem>, | ||
]; | ||
if (canSelectAll) { | ||
selectAllDropdownItems.push( | ||
<DropdownItem | ||
key="select-all" | ||
id="all" | ||
ouiaId="select-all" | ||
component="button" | ||
isDisabled={totalCount === 0 || areAllRowsSelected} | ||
onClick={handleSelectAll} | ||
> | ||
{`${__('Select all')} (${totalCount})`} | ||
</DropdownItem> | ||
); | ||
} | ||
|
||
return ( | ||
<Dropdown | ||
toggle={ | ||
<DropdownToggle | ||
onToggle={onSelectAllDropdownToggle} | ||
id="select-all-checkbox-dropdown-toggle" | ||
ouiaId="select-all-checkbox-dropdown-toggle" | ||
splitButtonItems={[ | ||
<DropdownToggleCheckbox | ||
className="tablewrapper-select-all-checkbox" | ||
key="tablewrapper-select-all-checkbox" | ||
ouiaId="select-all-checkbox-dropdown-toggle-checkbox" | ||
aria-label="Select all" | ||
onChange={checked => onSelectAllCheckboxChange(checked)} | ||
isChecked={selectionToggle} | ||
isDisabled={totalCount === 0 && selectedCount === 0} | ||
> | ||
{selectedCount > 0 && `${selectedCount} selected`} | ||
</DropdownToggleCheckbox>, | ||
]} | ||
/> | ||
} | ||
isOpen={isSelectAllDropdownOpen} | ||
dropdownItems={selectAllDropdownItems} | ||
id="selection-checkbox" | ||
ouiaId="selection-checkbox" | ||
/> | ||
); | ||
}; | ||
|
||
SelectAllCheckbox.propTypes = { | ||
selectedCount: PropTypes.number.isRequired, | ||
selectNone: PropTypes.func.isRequired, | ||
selectPage: PropTypes.func.isRequired, | ||
selectAll: PropTypes.func, | ||
pageRowCount: PropTypes.number, | ||
totalCount: PropTypes.number, | ||
areAllRowsOnPageSelected: PropTypes.bool.isRequired, | ||
areAllRowsSelected: PropTypes.bool.isRequired, | ||
}; | ||
|
||
SelectAllCheckbox.defaultProps = { | ||
selectAll: noop, | ||
pageRowCount: 0, | ||
totalCount: 0, | ||
}; | ||
|
||
export default SelectAllCheckbox; |
3 changes: 3 additions & 0 deletions
3
...k/assets/javascripts/react_app/components/PF4/TableIndexPage/Table/SelectAllCheckbox.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.tablewrapper-select-all-checkbox { | ||
font-weight: normal; | ||
} |
Oops, something went wrong.