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

List Manager Improvements #5259

Merged
merged 10 commits into from
Jan 9, 2025
212 changes: 162 additions & 50 deletions js/source/legacy/CXGN/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ CXGN.List = function () {



// Keep track of the rendered lists page number and sort column between refreshes
var render_lists_page = 0; // first page
var render_lists_order = [[0, "asc"]]; // sort by list name, ascending


CXGN.List.prototype = {
Expand Down Expand Up @@ -336,7 +339,11 @@ CXGN.List.prototype = {
},

renderLists: function(div) {
var type = jQuery('#render_lists_type').val();
var autocreated = jQuery("#render_lists_autocreated").is(":checked");
var lists = this.availableLists();
var types = this.allListTypes();

var html = '';
html = html + '<div class="well well-sm"><form class="form-horizontal"><div class="form-group form-group-sm"><label class="col-sm-3 control-label">Create New List: </label><div class="col-sm-9"><div class="input-group"><input id="add_list_input" type="text" class="form-control" placeholder="Create New List. Type New List Name Here" /><span class="input-group-btn"><button class="btn btn-primary btn-sm" type="button" id="add_list_button" value="new list">New List</button></span></div></div></div><div class="form-group form-group-sm"><label class="col-sm-3 control-label"></label><div class="col-sm-9">';
html = html + '<input id="add_list_input_description" type="text" class="form-control" placeholder="Description For New List" /></div></div></form></div>';
Expand All @@ -346,35 +353,79 @@ CXGN.List.prototype = {
jQuery('#'+div+'_div').html(html);
}

html += '<div class="well well-sm"><table id="private_list_data_table" class="table table-hover table-condensed">';
// List Table Container
html += "<div class='well'>";

// Table Header
html += "<div style='display: flex; flex-wrap: wrap; column-gap: 30px; justify-content: space-between; margin-bottom: 15px'>";

// Filter Container
html += "<div style='display: flex; flex-direction: column; row-gap: 15px'>"

// Filter by List Type
html += "<div style='display: flex; align-items: baseline; column-gap: 15px;'>"
html += "<p style='white-space: nowrap'><strong>Filter Lists by Type</strong>:</p>";
html += "<select id='render_lists_type' class='render_lists_filter form-control' style='max-width: 200px'>";
html += "<option value=''>Any</option>";
for ( let i = 0; i < types.length; i++ ) {
let selected = type && type === types[i][1] ? 'selected' : '';
html += "<option value='" + types[i][1] + "' " + selected + ">"+types[i][1]+"</option>";
}
html += "</select>";
html += "</div>";

// Autocreated filter
html += "<div style='display: flex; align-items: baseline; column-gap: 15px;'>";
html += "<p style='white-space: nowrap'><strong>Include Autocreated Lists</strong>:</p>";
let checked = autocreated ? 'checked' : ''
html += "<input id='render_lists_autocreated' class='render_lists_filter' type='checkbox' " + checked + " />";
html += "</div>";

// End Filter Container
html += "</div>";

// Multiple List Container
html += "<div id='list_group_select_action' style='flex-grow: 1; width: min-content; min-width: 500px;'></div>";

// End Header
html += "</div>";

// List Table
html += '<table id="private_list_data_table" class="table table-hover table-condensed">';
html += '<thead><tr><th>List Name</th><th>Description</th><th>Date Created</th><th>Date Modified</th><th>Count</th><th>Type</th><th>Validate</th><th>View</th><th>Delete</th><th>Download</th><th>Share</th><th>Group</th></tr></thead><tbody>';
for (var i = 0; i < lists.length; i++) {
html += '<tr><td><a href="javascript:showListItems(\'list_item_dialog\','+lists[i][0]+')"><b>'+lists[i][1]+'</b></a></td>';
html += '<td>'+lists[i][2]+'</td>';
html += '<td>'+lists[i][7]+'</td>';
html += '<td>'+lists[i][8]+'</td>';
html += '<td>'+lists[i][3]+'</td>';
html += '<td>'+lists[i][5]+'</td>';
html += '<td><a onclick="javascript:validateList(\''+lists[i][0]+'\',\''+lists[i][5]+'\')"><span class="glyphicon glyphicon-ok"></span></a></td>';
html += '<td><a title="View" id="view_list_'+lists[i][1]+'" href="javascript:showListItems(\'list_item_dialog\','+lists[i][0]+')"><span class="glyphicon glyphicon-th-list"></span></span></td>';
html += '<td><a title="Delete" id="delete_list_'+lists[i][1]+'" href="javascript:deleteList('+lists[i][0]+')"><span class="glyphicon glyphicon-remove"></span></a></td>';
html += '<td><a target="_blank" title="Download" id="download_list_'+lists[i][1]+'" href="/list/download?list_id='+lists[i][0]+'"><span class="glyphicon glyphicon-arrow-down"></span></a></td>';
if (lists[i][6] == 0){
html += '<td><a title="Make Public" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-share-alt"></span></a></td>';
} else if (lists[i][6] == 1){
html += '<td><a title="Make Private" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-ban-circle"></span></a></td>';
if ( (!type || type === lists[i][5]) && (autocreated || !(lists[i][2] || '').startsWith("Autocreated")) ) {
html += '<tr><td><a href="javascript:showListItems(\'list_item_dialog\','+lists[i][0]+')"><b>'+lists[i][1]+'</b></a></td>';
html += '<td>'+(lists[i][2] ? lists[i][2] : '')+'</td>';
html += '<td>'+(lists[i][7] ? new Date(lists[i][7]).toLocaleDateString() : '')+'</td>';
html += '<td>'+(lists[i][8] ? new Date(lists[i][8]).toLocaleDateString() : '')+'</td>';
html += '<td>'+(lists[i][3] ? lists[i][3] : '0')+'</td>';
html += '<td>'+(lists[i][5] ? lists[i][5] : '&lt;NOT SET&gt;')+'</td>';
html += '<td><a onclick="javascript:validateList(\''+lists[i][0]+'\',\''+lists[i][5]+'\')"><span class="glyphicon glyphicon-ok"></span></a></td>';
html += '<td><a title="View" id="view_list_'+lists[i][1]+'" href="javascript:showListItems(\'list_item_dialog\','+lists[i][0]+')"><span class="glyphicon glyphicon-th-list"></span></span></td>';
html += '<td><a title="Delete" id="delete_list_'+lists[i][1]+'" href="javascript:deleteList('+lists[i][0]+')"><span class="glyphicon glyphicon-remove"></span></a></td>';
html += '<td><a target="_blank" title="Download" id="download_list_'+lists[i][1]+'" href="/list/download?list_id='+lists[i][0]+'"><span class="glyphicon glyphicon-arrow-down"></span></a></td>';
if (lists[i][6] == 0){
html += '<td><a title="Make Public" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-share-alt"></span></a></td>';
} else if (lists[i][6] == 1){
html += '<td><a title="Make Private" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-ban-circle"></span></a></td>';
}
html += '<td><input type="checkbox" id="list_select_checkbox_'+lists[i][0]+'" name="list_select_checkbox" value="'+lists[i][0]+'"/></td></tr>';
}
html += '<td><input type="checkbox" id="list_select_checkbox_'+lists[i][0]+'" name="list_select_checkbox" value="'+lists[i][0]+'"/></td></tr>';
}
html = html + '</tbody></table></div>';
html += '<div id="list_group_select_action"></div>';
html += '</tbody></table>';
html += '</div>';

jQuery('#'+div+'_div').html(html);

jQuery('#private_list_data_table').DataTable({
var table = jQuery('#private_list_data_table').DataTable({
"destroy": true,
"columnDefs": [ { "orderable": false, "targets": [4,5,6,7,8] } ]
"columnDefs": [{ "orderable": false, "targets": [6,7,8,9,10,11] }],
"order": render_lists_order
});
table.page(render_lists_page).draw('page');
table.on('order', () => render_lists_order = table.order());
table.on('page', () => render_lists_page = table.page.info().page);

jQuery('#add_list_button').click(function() {
var lo = new CXGN.List();
Expand All @@ -392,26 +443,54 @@ CXGN.List.prototype = {
lo.renderPublicLists('public_list_dialog_div');
});

jQuery("input[name='list_select_checkbox']").click(function() {
function render_selected_lists_container() {
var total=jQuery("input[name='list_select_checkbox']:checked").length;
var list_group_select_action_html='';
if (total == 0) {
list_group_select_action_html += '';
} else {
if (total > 1) {
var selected = [];
jQuery("input[name='list_select_checkbox']:checked").each(function() {
selected.push(jQuery(this).attr('value'));
});

list_group_select_action_html = '<hr><div class="row well well-sm"><div class="col-sm-4">For Selected Lists:</div><div class="col-sm-8">';
if (total == 1) {
list_group_select_action_html += '<a id="delete_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:deleteSelectedListGroup(['+selected+'])">Delete</a>&nbsp;<a id="make_public_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePublicSelectedListGroup(['+selected+'])">Make Public</a>&nbsp;<a id="make_private_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePrivateSelectedListGroup(['+selected+'])">Make Private</a>';
} else if (total > 1) {
list_group_select_action_html += '<a id="delete_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:deleteSelectedListGroup(['+selected+'])">Delete</a>&nbsp;<a id="make_public_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePublicSelectedListGroup(['+selected+'])">Make Public</a>&nbsp;<a id="make_private_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePrivateSelectedListGroup(['+selected+'])">Make Private</a><br/><br/><div class="input-group input-group-sm"><input type="text" class="form-control" id="new_combined_list_name" placeholder="New List Name"><span class="input-group-btn"><a id="combine_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:combineSelectedListGroup(['+selected+'])">Combine</a></span></div>';
}
list_group_select_action_html += '</div></div>';
// Delete / Public / Private Functions
list_group_select_action_html += '<div class="row">';
list_group_select_action_html += '<div class="col-sm-4"><p><strong>Modify Selected Lists:</strong></p></div>';
list_group_select_action_html += '<div class="col-sm-8">';
list_group_select_action_html += '<a id="delete_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:deleteSelectedListGroup(['+selected+'])">Delete</a>&nbsp;<a id="make_public_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePublicSelectedListGroup(['+selected+'])">Make Public</a>&nbsp;<a id="make_private_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePrivateSelectedListGroup(['+selected+'])">Make Private</a>';
list_group_select_action_html += '</div>'; // end column
list_group_select_action_html += '</div>'; // end row

// Union / Intersection Icons
var unionIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 256 256"><path fill="currentColor" d="M172.91 83.09a78 78 0 1 0-89.82 89.82a78 78 0 1 0 89.82-89.82M226 160a65 65 0 0 1-.62 8.9l-53.76-53.77A77.8 77.8 0 0 0 174 96v-.49A66.1 66.1 0 0 1 226 160M45.31 53.79l55.5 55.5a77.9 77.9 0 0 0-12 19L34 73.48a66 66 0 0 1 11.31-19.69m88.92 96l-28-28a66.5 66.5 0 0 1 15.52-15.52l28 28a66.5 66.5 0 0 1-15.52 15.48ZM162 96a65.6 65.6 0 0 1-6 27.49L132.51 100A65.6 65.6 0 0 1 160 94h1.95c.05.7.05 1.35.05 2m-52.71 4.81l-55.5-55.5A66 66 0 0 1 73.48 34l54.8 54.81a77.9 77.9 0 0 0-18.99 12M94 160a65.6 65.6 0 0 1 6-27.49L123.49 156A65.6 65.6 0 0 1 96 162c-.65 0-1.3 0-2-.05zm52.71-4.81l55.5 55.5A66 66 0 0 1 182.52 222l-54.8-54.81a77.9 77.9 0 0 0 18.99-12m8.48-8.48a77.9 77.9 0 0 0 12-19L222 182.52a66 66 0 0 1-11.35 19.69Zm5.3-64.7H160a77.8 77.8 0 0 0-19.13 2.38L87.1 30.62A65 65 0 0 1 96 30a66.1 66.1 0 0 1 64.49 52ZM30 96a65 65 0 0 1 .62-8.9l53.76 53.77A77.8 77.8 0 0 0 82 160v.49A66.1 66.1 0 0 1 30 96m65.51 78H96a77.8 77.8 0 0 0 19.13-2.38l53.77 53.76a65 65 0 0 1-8.9.62a66.1 66.1 0 0 1-64.49-52"/></svg>';
var intersectionIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 256 256"><path fill="currentColor" d="M174.63 81.37a80 80 0 1 0-93.26 93.26a80 80 0 1 0 93.26-93.26M100.69 136L120 155.31A63.5 63.5 0 0 1 96 160a63.5 63.5 0 0 1 4.69-24m33.75 11.13l-25.57-25.57a64.7 64.7 0 0 1 12.69-12.69l25.57 25.57a64.7 64.7 0 0 1-12.69 12.69M155.31 120L136 100.69A63.5 63.5 0 0 1 160 96a63.5 63.5 0 0 1-4.69 24M32 96a64 64 0 0 1 126-16a80.08 80.08 0 0 0-77.95 78A64.11 64.11 0 0 1 32 96m128 128a64.11 64.11 0 0 1-62-48a80.08 80.08 0 0 0 78-78a64 64 0 0 1-16 126"/></svg>';

// Union / Intersection Functions
list_group_select_action_html += '<div class="row" style="margin-top: 15px">';
list_group_select_action_html += '<div class="col-sm-4"><p><strong>Combine List Items From Selected Lists to a New List:</strong></p></div>';
list_group_select_action_html += '<div class="col-sm-8">';
list_group_select_action_html += '<div class="input-group input-group-sm">'
list_group_select_action_html += '<input type="text" class="form-control" id="new_combined_list_name" placeholder="New List Name"><span class="input-group-btn">';
list_group_select_action_html += '<button id="combine_selected_list_group_union" class="btn btn-primary btn-sm" style="color:white; display: inline-flex; align-items: center; gap: 5px;" onclick="javascript:combineSelectedListGroup(['+selected+'], \'union\')">' + unionIcon + 'Union</button>';
list_group_select_action_html += '<button id="combine_selected_list_group_intersection" class="btn btn-primary btn-sm" style="color:white; display: inline-flex; align-items: center; gap: 5px;" onclick="javascript:combineSelectedListGroup(['+selected+'], \'intersection\')">' + intersectionIcon + 'Intersection</button>';
list_group_select_action_html += '</input></span>';
list_group_select_action_html += '</div>'; // End input group
list_group_select_action_html += '</div>'; // end column
list_group_select_action_html += '</div>'; // end row
}
else {
list_group_select_action_html += '<div style="width: 100%; text-align: right">';
list_group_select_action_html += '<p><em>Select 2 or more lists in the <strong>Group</strong> column to modify or combine them</em></p>';
list_group_select_action_html += '</div>';
}
jQuery("#list_group_select_action").html(list_group_select_action_html);
}
jQuery('body').on("click", "input[name='list_select_checkbox']", render_selected_lists_container);
render_selected_lists_container();

jQuery(".render_lists_filter").on("change", function() {
render_lists_page = 0;
var lo = new CXGN.List();
lo.renderLists('list_dialog');
});
},

Expand Down Expand Up @@ -1718,36 +1797,69 @@ function makePrivateSelectedListGroup(list_ids) {
}
}

function combineSelectedListGroup(list_ids) {
/**
* Combine the items from the selected lists and create a new list
* The items can be combined either using a union method or intersection method
* @param {Array[Integer]} list_ids Array of List IDs of Lists to combine
* @param {String} type Method of combining lists (either 'union' or 'intersection', union is default)
*/
function combineSelectedListGroup(list_ids, type = 'union') {
var arrayLength = list_ids.length;
var list_name = jQuery('#new_combined_list_name').val();
if (confirm('Combine selected lists into a new list called '+list_name+'?')) {
var arrayItems = [];
if ( !list_name || list_name === '' ) return alert("You must enter a new list name first");

if ( confirm('Combine selected lists into a new list called '+list_name+'?') ) {
var lo = new CXGN.List();
var first_list_type = lo.getListType(list_ids[0]);
var same_list_types = true;
for (var i=0; i<arrayLength; i++) {

// Check if the selected lists are the same list type
var list_types = [];
for ( var i=0; i<arrayLength; i++ ) {
var list_type = lo.getListType(list_ids[i]);
if (list_type != first_list_type) {
same_list_types = false;
if (!confirm('Are you sure you want to combine these list types: '+first_list_type+' and '+list_type)) {
return;
if ( !list_types.includes(list_type) ) list_types.push(list_type);
}
if ( list_types.length > 1 && !confirm('Are you sure you want to combine these list types: ' + list_types.join(', ')) ) return;

// Combine list items
var arrayItems = [];

// INTERSECTION
if ( type === 'intersection' ) {
var allListItems = [];
for ( var i=0; i<arrayLength; i++ ) {
list = lo.getListData(list_ids[i]);
var listItems = [];
for ( var j=0; j<list.elements.length; j++ ) {
listItems.push(list.elements[j][1]);
}
allListItems.push(listItems);
}
arrayItems = allListItems.reduce((result, array) => result.filter(value => array.includes(value)));
}
var new_list_id = lo.newList(list_name);
if (same_list_types == true) {
lo.setListType(new_list_id, first_list_type);
}
for (var i=0; i<arrayLength; i++) {
list = lo.getListData(list_ids[i]);
var numElements = list.elements.length;
for (var j=0; j<numElements; j++) {
arrayItems.push(list.elements[j][1]);

// UNION
else {
for ( var i=0; i<arrayLength; i++ ) {
list = lo.getListData(list_ids[i]);
for ( var j=0; j<list.elements.length; j++ ) {
arrayItems.push(list.elements[j][1]);
}
}
}

// Get unique set of items
arrayItems = [...new Set(arrayItems)];
if ( !arrayItems || arrayItems.length === 0 ) {
return alert("The selected lists don't have any list items in common. New list not created.");
}

// Add combined items to new list
var new_list_id = lo.newList(list_name);
if ( list_types.length === 1 ) {
lo.setListType(new_list_id, list_types[0]);
}
lo.addBulk(new_list_id, arrayItems);
lo.renderLists('list_dialog');
alert("Added " + arrayItems.length + " items to the new List " + list_name);
}
}

Expand Down
Loading
Loading