Skip to content

Commit

Permalink
Fixes #37398 - Extend TableIndexPage and TableHooks
Browse files Browse the repository at this point in the history
  with new capabilities for All Hosts page

- add the option to use `idColumnName` to `<RowSelectTd>`
- Add the option to supply your own pagination component in `<Table>`
- Add a `hasInteracted` state to `useBulkSelect`
- Add a `pushToHistory` option to `useSetParamsAndAPIAndSearch` to skip changing the browser URL
- Add `updateParamsByUrl` to `<TableIndexPage>` for the same reason
- Add `restrictedSearchQuery` to `<TableIndexPage>`
  • Loading branch information
jeremylenz committed Jun 11, 2024
1 parent f884bab commit b9c2dd0
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 52 deletions.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"dependencies": {
"@module-federation/utilities": "^1.7.0",
"@theforeman/vendor": "^13.0.1",
"@theforeman/vendor": "^13.1.0",
"graphql-tag": "^2.11.0",
"intl": "~1.2.5",
"jed": "^1.1.1",
Expand All @@ -30,11 +30,11 @@
},
"devDependencies": {
"@babel/core": "^7.7.0",
"@theforeman/builder": "^13.0.1",
"@theforeman/eslint-plugin-foreman": "^13.0.1",
"@theforeman/eslint-plugin-rules": "^13.0.1",
"@theforeman/test": "^13.0.1",
"@theforeman/vendor-dev": "^13.0.1",
"@theforeman/builder": "^13.1.0",
"@theforeman/eslint-plugin-foreman": "^13.1.0",
"@theforeman/eslint-plugin-rules": "^13.1.0",
"@theforeman/test": "^13.1.0",
"@theforeman/vendor-dev": "^13.1.0",
"@types/jest": "<27.0.0",
"argv-parse": "^1.0.1",
"babel-eslint": "^10.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Td } from '@patternfly/react-table';

export const RowSelectTd = ({ rowData, selectOne, isSelected }) => (
export const RowSelectTd = ({
rowData,
selectOne,
isSelected,
idColumnName = 'id',
}) => (
<Td
select={{
rowIndex: rowData.id,
rowIndex: rowData[idColumnName],
onSelect: (_event, isSelecting) => {
selectOne(isSelecting, rowData.id, rowData);
selectOne(isSelecting, rowData[idColumnName], rowData);
},
isSelected: isSelected(rowData.id),
isSelected: isSelected(rowData[idColumnName]),
disable: false,
}}
/>
Expand All @@ -19,4 +24,9 @@ RowSelectTd.propTypes = {
rowData: PropTypes.object.isRequired,
selectOne: PropTypes.func.isRequired,
isSelected: PropTypes.func.isRequired,
idColumnName: PropTypes.string,
};

RowSelectTd.defaultProps = {
idColumnName: 'id',
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const Bookmarks = ({
setModalOpen,
setModalClosed,
searchQuery,
bookmarksPosition,
}) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);

Expand Down Expand Up @@ -73,6 +74,7 @@ const Bookmarks = ({
/>
<Dropdown
ouiaId="bookmarks-dropdown"
position={bookmarksPosition}
isOpen={isDropdownOpen}
onSelect={() => setIsDropdownOpen(false)}
toggle={
Expand Down Expand Up @@ -107,6 +109,7 @@ Bookmarks.propTypes = {
setModalOpen: PropTypes.func.isRequired,
setModalClosed: PropTypes.func.isRequired,
searchQuery: PropTypes.string.isRequired,
bookmarksPosition: PropTypes.string,
};

Bookmarks.defaultProps = {
Expand All @@ -116,6 +119,7 @@ Bookmarks.defaultProps = {
status: null,
documentationUrl: '',
getBookmarks: noop,
bookmarksPosition: 'left',
};

export default Bookmarks;
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ConnectedBookmarks = ({
canCreate,
documentationUrl,
searchQuery,
bookmarksPosition,
}) => {
const key = `${BOOKMARKS}_${controller.toUpperCase()}`;
const modalID = getBookmarksModalId(id);
Expand Down Expand Up @@ -53,6 +54,7 @@ const ConnectedBookmarks = ({
setModalClosed={setModalClosed}
isModalOpen={isModalOpen}
searchQuery={searchQuery}
bookmarksPosition={bookmarksPosition}
/>
);
};
Expand All @@ -65,13 +67,15 @@ ConnectedBookmarks.propTypes = {
canCreate: PropTypes.bool,
documentationUrl: PropTypes.string,
searchQuery: PropTypes.string,
bookmarksPosition: PropTypes.string,
};

ConnectedBookmarks.defaultProps = {
id: 'searchBar',
canCreate: false,
documentationUrl: '',
searchQuery: '',
bookmarksPosition: 'left',
};

export const reducers = { bookmarksPF4: reducer };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const Table = ({
getActions,
isDeleteable,
itemCount,
selectOne,
isSelected,
params,
refreshData,
results,
Expand All @@ -32,8 +34,21 @@ export const Table = ({
isEmbedded,
showCheckboxes,
rowSelectTd,
idColumn,
children,
bottomPagination,
}) => {
if (!bottomPagination)
bottomPagination = (
<Pagination
key="table-bottom-pagination"
page={params.page}
perPage={params.perPage}
itemCount={itemCount}
onChange={onPagination}
updateParamsByUrl={!isEmbedded}
/>
);
const columnsToSortParams = {};
Object.keys(columns).forEach(key => {
if (columns[key].isSorted) {
Expand Down Expand Up @@ -129,7 +144,14 @@ export const Table = ({
const rowActions = actions(result);
return (
<Tr key={rowIndex} ouiaId={`table-row-${rowIndex}`} isHoverable>
{showCheckboxes && <RowSelectTd rowData={result} />}
{showCheckboxes && (
<RowSelectTd
rowData={result}
selectOne={selectOne}
isSelected={isSelected}
idColumnName={idColumn}
/>
)}
{columnNamesKeys.map(k => (
<Td key={k} dataLabel={keysToColumnNames[k]}>
{columns[k].wrapper
Expand All @@ -147,15 +169,7 @@ export const Table = ({
})}
</Tbody>
</TableComposable>
{results.length > 0 && !errorMessage && (
<Pagination
page={params.page}
perPage={params.perPage}
itemCount={itemCount}
onChange={onPagination}
updateParamsByUrl={!isEmbedded}
/>
)}
{results.length > 0 && !errorMessage && bottomPagination}
</>
);
};
Expand All @@ -179,7 +193,11 @@ Table.propTypes = {
isPending: PropTypes.bool.isRequired,
isEmbedded: PropTypes.bool,
rowSelectTd: PropTypes.func,
idColumn: PropTypes.string,
selectOne: PropTypes.func,
isSelected: PropTypes.func,
showCheckboxes: PropTypes.bool,
bottomPagination: PropTypes.node,
};

Table.defaultProps = {
Expand All @@ -191,5 +209,9 @@ Table.defaultProps = {
results: [],
isEmbedded: false,
rowSelectTd: noop,
idColumn: 'id',
selectOne: noop,
isSelected: noop,
showCheckboxes: false,
bottomPagination: null,
};
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,12 @@ export const useBulkSelect = ({
idColumn,
isSelectable,
});
const [hasInteracted, setHasInteracted] = useState(false);
const exclusionSet = useSet(initialExclusionArry);
const [searchQuery, updateSearchQuery] = useState(initialSearchQuery);
const [selectAllMode, setSelectAllMode] = useState(initialSelectAllMode);
const selectedCount = selectAllMode
? Number(metadata.selectable || metadata.total) - exclusionSet.size
? Number(metadata.selectable ?? metadata.total) - exclusionSet.size
: selectOptions.selectedCount;

const areAllRowsOnPageSelected = () =>
Expand All @@ -209,13 +210,15 @@ export const useBulkSelect = ({
const selectPage = () => {
setSelectAllMode(false);
selectOptions.selectPage();
setHasInteracted(true);
};

const selectNone = useCallback(() => {
setSelectAllMode(false);
exclusionSet.clear();
inclusionSet.clear();
selectOptions.clearSelectedResults();
setHasInteracted(true);
}, [exclusionSet, inclusionSet, selectOptions]);

const selectOne = (isRowSelected, id, data) => {
Expand All @@ -228,20 +231,26 @@ export const useBulkSelect = ({
} else {
selectOptions.selectOne(isRowSelected, id, data);
}
setHasInteracted(true);
};

const selectAll = checked => {
setSelectAllMode(checked);
if (checked) {
exclusionSet.clear();
} else {
inclusionSet.clear();
}
};
const selectAll = useCallback(
checked => {
setSelectAllMode(checked);
if (checked) {
exclusionSet.clear();
} else {
inclusionSet.clear();
}
setHasInteracted(true);
},
[exclusionSet, inclusionSet]
);

const selectDefault = () => {
selectNone();
selectOptions.selectDefault();
setHasInteracted(true);
};

const fetchBulkParams = ({
Expand Down Expand Up @@ -301,6 +310,8 @@ export const useBulkSelect = ({
areAllRowsSelected,
inclusionSet,
exclusionSet,
hasInteracted,
setHasInteracted,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,30 +44,39 @@ A hook that stores the 'params' state and returns the setParamsAndAPI and setSea
@param {Object}{apiOptions} - options object. Should include { key: HOSTS_API_KEY }; see APIRequest.js for more details
@param {Function}{setAPIOptions} - Pass in the setAPIOptions function returned from useAPI.
@param {Function}{updateSearchQuery} - Pass in the updateSearchQuery function returned from useBulkSelect.
@param {Boolean}{pushToHistory} - If true, keep the browser url params in sync with search and pagination
@return {Object} - returns the setParamsAndAPI and setSearch functions, and current params
@return {Function}{setParamsAndAPI} - function to set the params and API options
@return {Function}{setSearch} - function to set the search query
@return {Object}{params} - current params state
*/
export const useSetParamsAndApiAndSearch = ({
defaultParams,
apiOptions,
setAPIOptions,
updateSearchQuery,
pushToHistory = true,
}) => {
const [params, setParams] = useState(defaultParams);
const history = useHistory();
const setParamsAndAPI = newParams => {
// add url edit params to the new params
const uri = new URI();
uri.setSearch(newParams);
history.push({ search: uri.search() });
if (pushToHistory) {
const uri = new URI();
uri.setSearch(newParams);
history.push({ search: uri.search() });
}
setParams(newParams);
setAPIOptions({ ...apiOptions, params: newParams });
};

const setSearch = newSearch => {
const uri = new URI();
uri.setSearch(newSearch);
if (pushToHistory) {
const uri = new URI();
uri.setSearch(newSearch);
history.push({ search: uri.search() });
}
updateSearchQuery(newSearch.search);
history.push({ search: uri.search() });
setParamsAndAPI({ ...params, ...newSearch });
};

Expand Down
Loading

0 comments on commit b9c2dd0

Please sign in to comment.