Skip to content

Commit

Permalink
Fixes #35287 - Create column selector on host index page
Browse files Browse the repository at this point in the history
  • Loading branch information
pkoprda committed Oct 17, 2022
1 parent 39771f9 commit 9785b1e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 111 deletions.
23 changes: 10 additions & 13 deletions app/helpers/pagelets_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ def th_content(col)
def mount_column_selector
url = "#{api_users_path}/#{User.current[:id]}/table_preferences"
has_preference = !@selected_columns.nil?
@selected_columns = Pagelets::Manager.pagelets_at('hosts/_list', :hosts_table_column_header).map { |pt| pt.opts[:key].to_s if pt.opts[:key] }.to_a.compact unless has_preference
columns = columns_view
react_component("ColumnSelector", data:
{
url: url,
controller: controller_name,
columns: columns_view,
columns: columns,
initialColumns: columns,
hasPreference: has_preference,
tableHasName: table_exists?,
}
)
end
Expand All @@ -90,22 +90,19 @@ def defined_columns
{
key: pt.opts[:key],
label: pt.opts[:label],
profiles: pt.profiles.map { |pr| pr.label },
checked: @selected_columns&.include?(pt.opts[:key].to_s),
profiles: pt.profiles.map { |pr| pr.id },
checked: @selected_columns ? @selected_columns.include?(pt.opts[:key].to_s) : pt.profiles.any? { |profile| profile.default? },
}
end.compact
end

def defined_categories(defined_cols)
defined_cols.map { |col| col[:profiles] }.flatten.uniq
def defined_categories(columns)
columns.map { |col| col[:profiles] }.flatten.uniq
end

def all_checked?(category)
!category.any? { |column| !column[:checkProps][:checked] }
end

def table_exists?
User.current.table_preferences.find_by(name: controller_name)&.name&.present?
return true if category.all? { |column| column[:checkProps][:checked] }
category.any? { |column| column[:checkProps][:checked] } ? nil : false
end

def columns_view
Expand All @@ -125,7 +122,7 @@ def columns_view
name: column[:label],
key: column[:key],
checkProps: { checked: column[:checked] },
}
} if column[:profiles].first == category[:key]
end
category[:checkProps][:checked] = all_checked?(category[:children])
end
Expand Down
2 changes: 1 addition & 1 deletion app/registries/pagelets/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def pagelets_at(*args)
end

def with_profile(id, label, opts, &block)
profile = Profile.new(id, label.downcase, self, opts)
profile = Profile.new(id.to_s, label, self, opts)
profile.instance_exec(&block)
profile.pagelets.each do |pagelet|
add_pagelet(*pagelet)
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/_application_content.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</div>
<div id="title_action" class= <%= searchable? ? "col-md-6" : "col-md-8" %>>
<% if filter_columns? %>
<div class="col-md-1">
<div class="pull-left">
<%= mount_column_selector %>
<%= yield(:column_selector) %>&nbsp;
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import { Button, Modal, ModalVariant, TreeView } from '@patternfly/react-core';
import { translate as __ } from '../../common/I18n';
import API from '../../API';
import { changeQuery } from '../../common/urlHelpers';
import './column-selector.scss';

const ColumnSelector = props => {
const {
data: { url, controller, columns, hasPreference, tableHasName },
data: { url, controller, columns, initialColumns, hasPreference },
} = props;

const [isModalOpen, setModalOpen] = useState(false);
Expand All @@ -17,52 +16,34 @@ const ColumnSelector = props => {

useEffect(() => {
if (!tablePreference) {
tableHasName ? updateTablePreference() : createTablePreference();
createTablePreference();
setTablePreference(true);
}

function createTablePreference() {
API.post(url, { name: 'hosts', columns: getColumnKeys() });
}
}, [
url,
controller,
columns,
tablePreference,
updateTablePreference,
tableHasName,
selectedColumns,
getColumnKeys,
]);
}, [url, tablePreference, selectedColumns, getColumnKeys, initialColumns]);

const getColumnKeys = useCallback(() => {
const keys = columns
.find(category => category.key)
.children.map(col => {
if (col.checkProps.checked) {
return col.key;
const keys = selectedColumns
.map(category => category.children)
.flat()
.map(column => {
if (column.checkProps.checked) {
return column.key;
}
return null;
})
.filter(item => item);
return keys;
}, [columns]);
}, [selectedColumns]);

const updateTablePreference = useCallback(() => {
API.put([url, controller].join('/'), { columns: getColumnKeys() });
}, [url, controller, getColumnKeys]);

const onClose = () => {
setModalOpen(!isModalOpen);
};

const onCancel = () => {
setSelectedColumns(columns);
setModalOpen(!isModalOpen);
changeQuery({});
};

const filterItems = (item, checkedItem) => {
const filterItems = useCallback((item, checkedItem) => {
if (item.key === checkedItem.key) {
return true;
}
Expand All @@ -75,9 +56,9 @@ const ColumnSelector = props => {
}

return null;
};
}, []);

const flattenTree = tree => {
const flattenTree = useCallback(tree => {
let result = [];
tree.forEach(item => {
result.push(item);
Expand All @@ -86,95 +67,98 @@ const ColumnSelector = props => {
}
});
return result;
}, []);

const onClose = () => {
setModalOpen(!isModalOpen);
};

const unCheck = treeViewItem => {
treeViewItem.checkProps.checked = false;
const onCancel = () => {
setSelectedColumns(initialColumns);
setModalOpen(!isModalOpen);
};

const isDisabled = () => {
const hasPartialCheck = selectedColumns.map(
item => item.checkProps.checked
);
return hasPartialCheck.every(el => el === false);
};

const updateCheckBox = (treeViewItem, checked = true) => {
treeViewItem.checkProps.checked = checked;
if (treeViewItem.children) {
treeViewItem.children.forEach(item => {
item.checkProps.checked = false;
item.checkProps.checked = checked;
});
}
};

const onCheck = (evt, treeViewItem) => {
const { checked } = evt.target;
const checkedItemTree = columns
const checkedItemTree = selectedColumns
.map(column => Object.assign({}, column))
.filter(item => filterItems(item, treeViewItem));
const flatCheckedItems = flattenTree(checkedItemTree);

if (checked) {
updateCheckBox(treeViewItem);
setSelectedColumns(
selectedColumns.concat(
flatCheckedItems.filter(
item => !selectedColumns.some(i => i.key === item.key)
selectedColumns
.concat(
flatCheckedItems.filter(
item => !selectedColumns.some(i => i.key === item.key)
)
)
)
.filter(item => item.children)
);
} else {
unCheck(treeViewItem);
updateCheckBox(treeViewItem, false);
setSelectedColumns(
selectedColumns.filter(
item => !flatCheckedItems.some(i => i.key === item.key)
selectedColumns.filter(item =>
flatCheckedItems.some(i => i.key === item.key)
)
);
}
selectedColumns.map(category => areDescendantsChecked(category));
};

const isChecked = dataItem =>
selectedColumns.some(item => item.key === dataItem.key);
const areAllDescendantsChecked = dataItem =>
dataItem.children
? dataItem.children.every(child => areAllDescendantsChecked(child))
: isChecked(dataItem);
const areSomeDescendantsChecked = dataItem =>
dataItem.children
? dataItem.children.some(child => areSomeDescendantsChecked(child))
: isChecked(dataItem);

const mapTree = item => {
const hasCheck = areAllDescendantsChecked(item);

if (hasCheck) {
item.checkProps.checked = true;
} else {
const hasPartialCheck = areSomeDescendantsChecked(item);
if (hasPartialCheck) {
item.checkProps.checked = null;
const isChecked = dataItem => dataItem.checkProps.checked;
const areDescendantsChecked = dataItem => {
if (dataItem.children) {
if (dataItem.children.every(child => isChecked(child))) {
dataItem.checkProps.checked = true;
} else if (dataItem.children.some(child => isChecked(child))) {
dataItem.checkProps.checked = null;
} else {
dataItem.checkProps.checked = false;
}
}

if (item.children) {
return {
...item,
children: item.children.map(child => mapTree(child)),
};
}

return item;
};

return (
<div className="pf-c-select-input">
<div className="column-selector pf-c-input-group" id="column-selector">
<div className="pf-c-input-group" id="column-selector">
<Button
id="btn-filter"
variant="tertiary"
variant="secondary"
className="pull-left"
onClick={() => onClose()}
>
{__('Filter columns')}
{__('Manage columns')}
</Button>
<Modal
variant={ModalVariant.small}
title={__('Filter columns')}
title={__('Manage columns')}
isOpen={isModalOpen}
onClose={onClose}
description={__('Select columns to display in the table')}
position="top"
actions={[
<Button
key="save"
variant="primary"
isDisabled={isDisabled()}
onClick={() => {
updateTablePreference();
changeQuery({});
Expand All @@ -187,11 +171,7 @@ const ColumnSelector = props => {
</Button>,
]}
>
<TreeView
data={columns.map(category => mapTree(category))}
onCheck={onCheck}
hasChecks
/>
<TreeView data={selectedColumns} onCheck={onCheck} hasChecks />
</Modal>
</div>
</div>
Expand All @@ -203,8 +183,8 @@ ColumnSelector.propTypes = {
url: PropTypes.string,
controller: PropTypes.string,
columns: PropTypes.arrayOf(PropTypes.object),
initialColumns: PropTypes.arrayOf(PropTypes.object),
hasPreference: PropTypes.bool,
tableHasName: PropTypes.bool,
}),
};

Expand All @@ -213,8 +193,8 @@ ColumnSelector.defaultProps = {
url: '',
controller: '',
columns: [],
initialColumns: [],
hasPreference: false,
tableHasName: false,
},
};

Expand Down

This file was deleted.

0 comments on commit 9785b1e

Please sign in to comment.