Skip to content

Commit

Permalink
Merge pull request #5259 from solgenomics/topic/list_improvements
Browse files Browse the repository at this point in the history
List Manager Improvements
  • Loading branch information
lukasmueller authored Jan 9, 2025
2 parents 6e8a143 + 5bcec4c commit 0571a11
Show file tree
Hide file tree
Showing 3 changed files with 347 additions and 207 deletions.
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

0 comments on commit 0571a11

Please sign in to comment.