Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Tailorings): Implement group selection #2306

Merged
merged 1 commit into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ const useAsyncTableTools = (items, columns, options = {}) => {
...sortableTableProps,
...bulkSelectTableProps,
...expandableTableProps,
...tableViewTableProps,
...tablePropsOption,
onSelect: bulkSelectTableProps?.onSelect || tablePropsOption?.onSelect,
actionResolver: actionResolverEnabled && actionResolver,
...tableViewTableProps,
}),
[
managedColumns,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ exports[`useBulkSelect returns a bulk select configuration 1`] = `
"onSelect": undefined,
},
"tableView": {
"clear": [Function],
"deselect": [Function],
"markRowSelected": [Function],
"select": [Function],
"selectOne": [Function],
"set": [Function],
},
"toolbarProps": {
"bulkSelect": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const useBulkSelect = ({

return enableBulkSelect
? {
tableView: { markRowSelected },
tableView: { markRowSelected, selectOne, set, select, deselect, clear },
tableProps: {
onSelect: total > 0 ? selectOne : undefined,
canSelectAll: false,
Expand Down
53 changes: 53 additions & 0 deletions src/Frameworks/AsyncTableTools/hooks/useTableView/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { treeRow } from '@patternfly/react-table';

export const treeColumns = (columns, onCollapse, onSelect) => [
{
...columns[0],
cellTransforms: [
...(columns[0].cellTransforms || []),
treeRow(
(...args) => onCollapse?.(...args),
onSelect && ((...args) => onSelect?.(...args))
),
],
},
...columns.slice(1),
];

export const collectLeaves = (tableTree, itemId) => {
const pickBranch = (basket, branch, _idx, _arr, inBranchArg) => {
const inBranch = inBranchArg || (itemId ? branch.itemId === itemId : true);
const twigLeaves = branch?.twigs?.flatMap((twig) =>
pickBranch([], twig, _idx, _arr, inBranch)
);

return [
...basket,
...(twigLeaves || []),
...(inBranch ? branch.leaves || [] : []),
...(inBranch ? (branch.leave ? [branch.leave] : []) : []),
];
};

return tableTree.reduce(pickBranch, []);
};

export const getOnTreeSelect = (options) => {
const { select, deselect } = options.bulkSelect || {};

return (
options.bulkSelect &&
((...args) => {
const row = args[4];
const idsForSelect = row.isTreeBranch
? collectLeaves(options.tableTree, row.itemId).map(
({ itemId }) => itemId
)
: row.itemId;

!(row.props?.isChecked || row.isChecked)
? select(idsForSelect)
: deselect(idsForSelect);
})
);
};
26 changes: 9 additions & 17 deletions src/Frameworks/AsyncTableTools/hooks/useTableView/views/index.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
import React from 'react';
import { ListIcon, TreeviewIcon } from '@patternfly/react-icons';
import { Spinner } from '@patternfly/react-core';
import { treeRow } from '@patternfly/react-table';
import NoResultsTable from 'Utilities/hooks/useTableTools/Components/NoResultsTable';

import { treeColumns, getOnTreeSelect } from '../helpers';
import rowsBuilder from './rowsBuilder';
import treeChopper from './treeChopper';

const treeColumns = (columns, onCollapse) => [
{
...columns[0],
cellTransforms: [
...(columns[0].cellTransforms || []),
treeRow(
(...args) => onCollapse?.(...args)
// TODO add Selection feature
),
],
},
...columns.slice(1),
];

const views = {
loading: {
tableProps: (_items, columns) => ({
Expand Down Expand Up @@ -70,19 +55,26 @@ const views = {
tree: {
tableProps: (items, columns, options) => {
const rows = treeChopper(items, columns, options);
const cells = treeColumns(columns, options.expandable.onCollapse);
const onSelect = getOnTreeSelect(options);
const cells = treeColumns(
columns,
options.expandable?.onCollapse,
options.bulkSelect && onSelect
);

return rows
? {
cells,
rows,
isTreeTable: true,
onSelect: undefined,
}
: {};
},
icon: TreeviewIcon,
toolbarProps: () => ({
variant: 'compact',
bulkSelect: undefined,
}),
checkOptions: ({ tableTree }) => !!tableTree,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const childRowForItem = (item, _idx, DetailsComponent, colSpan) => ({
),
props: {
...(colSpan ? { colSpan } : {}),
// TODO This removes the checkbox, however this should maybe be fixed differently
className: 'compliance-rule-details',
},
},
],
Expand Down Expand Up @@ -78,7 +80,7 @@ const buildTreeBranch = (
...item,
...(items?.find(({ id }) => id === item.itemId) || {}),
props: {
// ...(selectable ? { isChecked: item.rowProps?.selected } : {}),
...(selectable ? { isChecked: item.isChecked } : {}),
isExpanded: openItems.includes(item.itemId) || false,
'aria-level': nextLevel,
'aria-setsize': 1,
Expand Down Expand Up @@ -114,27 +116,27 @@ const buildTreeBranch = (
})
: [];

// const isChecked = () => {
// const anySprouts = leaves.length > 0 || twigs.length > 0;
// const allSprouts = [...(twigs || []), ...(leaves || [])];
// if (
// anySprouts &&
// allSprouts
// .filter(({ props: { isDetailsRow } }) => !isDetailsRow)
// .every((leaf) => leaf.props.isChecked === true)
// ) {
// return true;
// }
//
// if (
// anySprouts &&
// allSprouts.some((leave) => leave.props.isChecked === true)
// ) {
// return null;
// }
//
// return false;
// };
const isChecked = () => {
const anySprouts = leaves.length > 0 || twigs.length > 0;
const allSprouts = [...(twigs || []), ...(leaves || [])];
if (
anySprouts &&
allSprouts
.filter(({ props: { isDetailsRow } }) => !isDetailsRow)
.every((leaf) => leaf.props.isChecked === true)
) {
return true;
}

if (
anySprouts &&
allSprouts.some((leave) => leave.props.isChecked === true)
) {
return null;
}

return false;
};

const branchRow =
level === 1 || twigs.length > 0 || leaves.length > 0
Expand All @@ -150,11 +152,11 @@ const buildTreeBranch = (
isTreeBranch: true,
isExpanded,
props: {
// ...(selectable
// ? {
// isChecked: isChecked(),
// }
// : {}),
...(selectable
? {
isChecked: isChecked(),
}
: {}),
isExpanded,
'aria-level': level,
'aria-setsize':
Expand Down Expand Up @@ -210,7 +212,7 @@ const treeChopper = (items, columns, options = {}) => {
const {
tableTree,
expandable: { openItems } = {},
// bulkSelect: { markRowSelected } = {}, // TODO Enable selection for groups and rows in groups
bulkSelect: { markRowSelected } = {},
detailsComponent,
} = options;

Expand All @@ -219,9 +221,9 @@ const treeChopper = (items, columns, options = {}) => {
items,
columns,
openItems,
[],
[markRowSelected],
detailsComponent,
false
true
);

return choppedTree;
Expand Down
3 changes: 1 addition & 2 deletions src/PresentationalComponents/RulesTable/RulesTableRest.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const RulesTable = ({
function Row(props) {
// eslint-disable-next-line react/prop-types
const { itemId, valueDefinitions } = props?.item || {};

const rule = rules?.find(({ id }) => itemId === id);
const ruleValueDefinitions = rule?.value_checks?.map((checkId) =>
valueDefinitions?.data?.find(({ id }) => id === checkId)
Expand Down Expand Up @@ -108,7 +107,7 @@ const RulesTable = ({
]);

const itemsWithValueDefinitions = useMemo(
() => rules?.map((rule) => ({ ...rule, rowProps: { valueDefinitions } })),
() => rules?.map((rule) => ({ ...rule, valueDefinitions })),
[rules, valueDefinitions]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ const TailoringTab = ({
ruleGroups && (tailoringRuleTree || securityGuideRuleTree)
? buildTreeTable(
tailoringRuleTree || securityGuideRuleTree,
ruleGroups?.data
ruleGroups?.data,
preselected
)
: undefined;

Expand Down Expand Up @@ -151,11 +152,7 @@ const TailoringTab = ({
}}
onRuleValueReset={onRuleValueReset}
onValueOverrideSave={onValueSave}
onSelect={
onSelect && tableState?.tableState?.tableView !== 'tree'
? onSelectRule
: undefined
}
onSelect={onSelect ? onSelectRule : undefined}
selectedRules={preselected}
options={{
exporter,
Expand Down
3 changes: 2 additions & 1 deletion src/PresentationalComponents/Tailorings/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const eventKey = ({ id, os_minor_version }) =>
`tailoring-${id}-${os_minor_version}`;

export const buildTreeTable = (ruleTree, ruleGroups) => {
export const buildTreeTable = (ruleTree, ruleGroups, selected) => {
const growTree = (ruleTree) =>
ruleTree
.map((branch) => {
Expand All @@ -22,6 +22,7 @@ export const buildTreeTable = (ruleTree, ruleGroups) => {
} else {
return {
itemId: branch.id,
...(selected ? { isChecked: selected.includes(branch.id) } : {}),
...branch,
};
}
Expand Down
Loading