From 4c277cd685a3acc728296e949adb85feb2da4632 Mon Sep 17 00:00:00 2001 From: Inga Kirschnick <inga.kirschnick@uni-bielefeld.de> Date: Tue, 6 Jun 2023 15:39:47 +0200 Subject: [PATCH] Corpus List update --- app/static/js/ResourceLists/CorpusFileList.js | 2 +- app/static/js/ResourceLists/CorpusList.js | 83 +++++++++++-------- .../DetailledPublicCorpusList.js | 71 ++++++++++++++++ .../js/ResourceLists/PublicCorpusList.js | 22 +++-- app/templates/_scripts.html.j2 | 3 +- app/templates/corpora/public_corpus.html.j2 | 2 +- app/templates/main/dashboard.html.j2 | 2 +- app/templates/main/social_area.html.j2 | 4 +- app/templates/users/user.html.j2 | 4 +- 9 files changed, 142 insertions(+), 51 deletions(-) create mode 100644 app/static/js/ResourceLists/DetailledPublicCorpusList.js diff --git a/app/static/js/ResourceLists/CorpusFileList.js b/app/static/js/ResourceLists/CorpusFileList.js index 07a2eaca..5957a140 100644 --- a/app/static/js/ResourceLists/CorpusFileList.js +++ b/app/static/js/ResourceLists/CorpusFileList.js @@ -158,7 +158,7 @@ class CorpusFileList extends ResourceList { window.location.reload(); }); } else { - Requests.corpora.entity.followers.entity.delete(this.corpusId, itemId); + Requests.corpora.entity.files.ent.delete(this.corpusId, itemId) } }); modal.open(); diff --git a/app/static/js/ResourceLists/CorpusList.js b/app/static/js/ResourceLists/CorpusList.js index a95533fe..7988cb85 100644 --- a/app/static/js/ResourceLists/CorpusList.js +++ b/app/static/js/ResourceLists/CorpusList.js @@ -26,9 +26,9 @@ class CorpusList extends ResourceList { get item() { return (values) => { return ` - <tr class="${values['is-owner'] ? '' : 'deep-purple lighten-5'} list-item"> + <tr class="list-item"> <td> - <label class="list-action-trigger ${values['is-owner'] ? '' : 'hide'}" data-list-action="select"> + <label class="list-action-trigger" data-list-action="select"> <input class="select-checkbox" type="checkbox"> <span class="disable-on-click"></span> </label> @@ -36,8 +36,9 @@ class CorpusList extends ResourceList { <td><b class="title"></b><br><i class="description"></i></td> <td><span class="owner"></span></td> <td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td> + <td>${values['current-user-is-following'] ? '<span><i class="left material-icons">visibility</i>Following</span>' : ''}</td> <td class="right-align"> - <a class="list-action-trigger btn-floating red waves-effect waves-light ${values['is-owner'] ? '' : 'hide'}" data-list-action="delete-request"><i class="material-icons">delete</i></a> + <a class="list-action-trigger btn-floating red waves-effect waves-light" data-list-action="delete-request"><i class="material-icons">delete</i></a> <a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a> </td> </tr> @@ -53,6 +54,7 @@ class CorpusList extends ResourceList { 'description', 'title', 'owner', + 'current-user-is-following' ]; } @@ -79,6 +81,7 @@ class CorpusList extends ResourceList { <th>Title and Description</th> <th>Owner</th> <th>Status</th> + <th></th> <th class="right-align"> <a class="corpus-list-selection-action-trigger btn-floating red waves-effect waves-light hide" data-selection-action="delete"><i class="material-icons">delete</i></a> </th> @@ -98,7 +101,8 @@ class CorpusList extends ResourceList { 'status': corpus.status, 'title': corpus.title, 'owner': corpus.user.username, - 'is-owner': corpus.user.id === this.userId ? true : false + 'is-owner': corpus.user.id === this.userId ? true : false, + 'current-user-is-following': Object.values(corpus.corpus_follower_associations).some(association => association.follower.id === currentUserId) }; } @@ -120,7 +124,7 @@ class CorpusList extends ResourceList { <div class="modal"> <div class="modal-content"> <h4>Confirm Corpus deletion</h4> - <p>Do you really want to delete the Corpus <b>${values.title}</b>? All files will be permanently deleted!</p> + <p>Do you really want to ${values['is-owner'] ? 'delete' : 'unfollow'} the Corpus <b>${values.title}</b>? ${values['is-owner'] ? 'All files will be permanently deleted!' : ''}</p> </div> <div class="modal-footer"> <a class="btn modal-close waves-effect waves-light">Cancel</a> @@ -142,7 +146,14 @@ class CorpusList extends ResourceList { ); let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); confirmElement.addEventListener('click', (event) => { - Requests.corpora.entity.delete(itemId); + if (!values['is-owner']) { + Requests.corpora.entity.followers.entity.delete(itemId, currentUserId) + .then((response) => { + window.location.reload(); + }); + } else { + Requests.corpora.entity.delete(itemId); + } }); modal.open(); break; @@ -152,7 +163,6 @@ class CorpusList extends ResourceList { break; } case 'select': { - if (event.target.checked) { this.selectedItemIds.add(itemId); } else { @@ -169,7 +179,7 @@ class CorpusList extends ResourceList { onSelectionAction(event) { let selectionActionElement = event.target.closest('.corpus-list-selection-action-trigger[data-selection-action]'); let selectionAction = selectionActionElement.dataset.selectionAction; - let items = Array.from(this.listjs.items).filter(item => item._values["is-owner"] === true); + let items = Array.from(this.listjs.items); let selectableItems = Array.from(items) .filter(item => item.elm) .map(item => item.elm.querySelector('.select-checkbox[type="checkbox"]')); @@ -195,10 +205,11 @@ class CorpusList extends ResourceList { ` <div class="modal"> <div class="modal-content"> - <h4>Confirm Corpus File deletion</h4> - <p>Do you really want to delete this Corpora?</p> - <ul id="selected-items-list"></ul> - <p>All corpora will be permanently deleted!</p> + <h4>Confirm Corpus deletion</h4> + <p>Do you really want to delete this Corpora? <i>All corpora will be permanently deleted!</i></p> + <ul id="selected-deletion-items-list"></ul> + <p>Do you really want to unfollow this Corpora?</p> + <ul id="selected-unfollow-items-list"></ul> </div> <div class="modal-footer"> <a class="btn modal-close waves-effect waves-light">Cancel</a> @@ -208,12 +219,17 @@ class CorpusList extends ResourceList { ` ); document.querySelector('#modals').appendChild(modalElement); - let itemList = document.querySelector('#selected-items-list'); + let itemDeletionList = document.querySelector('#selected-deletion-items-list'); + let itemUnfollowList = document.querySelector('#selected-unfollow-items-list'); this.selectedItemIds.forEach(selectedItemId => { let listItem = this.listjs.get('id', selectedItemId)[0].elm; let values = this.listjs.get('id', listItem.dataset.id)[0].values(); let itemElement = Utils.HTMLToElement(`<li> - ${values.title}</li>`); - itemList.appendChild(itemElement); + if (!values['is-owner']) { + itemUnfollowList.appendChild(itemElement); + } else { + itemDeletionList.appendChild(itemElement); + } }); let modal = M.Modal.init( modalElement, @@ -228,7 +244,13 @@ class CorpusList extends ResourceList { let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); confirmElement.addEventListener('click', (event) => { this.selectedItemIds.forEach(selectedItemId => { - Requests.corpora.entity.delete(selectedItemId); + let listItem = this.listjs.get('id', selectedItemId)[0].elm; + let values = this.listjs.get('id', listItem.dataset.id)[0].values(); + if (!values['is-owner']) { + Requests.corpora.entity.followers.entity.delete(selectedItemId, currentUserId); + } else { + Requests.corpora.entity.delete(selectedItemId); + } }); this.selectedItemIds.clear(); this.renderingItemSelection(); @@ -248,23 +270,17 @@ class CorpusList extends ResourceList { let actionButtons = []; Object.values(selectableItems).forEach(selectableItem => { - if (selectableItem._values["is-owner"] === false && this.selectedItemIds.size > 0) { - selectableItem.elm.classList.add('hide'); - } else if (selectableItem._values["is-owner"] === false && this.selectedItemIds.size === 0) { - selectableItem.elm.classList.remove('hide'); - } else { - if (selectableItem.elm) { - let checkbox = selectableItem.elm.querySelector('.select-checkbox[type="checkbox"]'); - if (checkbox.checked) { - selectableItem.elm.classList.add('grey', 'lighten-3'); - } else { - selectableItem.elm.classList.remove('grey', 'lighten-3'); - } - let itemActionButtons = selectableItem.elm.querySelectorAll('.list-action-trigger:not([data-list-action="select"])'); - itemActionButtons.forEach(itemActionButton => { - actionButtons.push(itemActionButton); - }); + if (selectableItem.elm) { + let checkbox = selectableItem.elm.querySelector('.select-checkbox[type="checkbox"]'); + if (checkbox.checked) { + selectableItem.elm.classList.add('grey', 'lighten-3'); + } else { + selectableItem.elm.classList.remove('grey', 'lighten-3'); } + let itemActionButtons = selectableItem.elm.querySelectorAll('.list-action-trigger:not([data-list-action="select"])'); + itemActionButtons.forEach(itemActionButton => { + actionButtons.push(itemActionButton); + }); } }); // Hide item action buttons if > 0 item is selected and show selection action buttons @@ -285,11 +301,10 @@ class CorpusList extends ResourceList { } // Check select all checkbox if all items are selected - let filteredItems = Object.values(selectableItems).filter(item => item._values["is-owner"] === true) let selectAllCheckbox = document.querySelector('.corpus-list-select-all-checkbox[type="checkbox"]'); - if (filteredItems.length === this.selectedItemIds.size && selectAllCheckbox.checked === false) { + if (selectableItems.length === this.selectedItemIds.size && selectAllCheckbox.checked === false) { selectAllCheckbox.checked = true; - } else if (filteredItems.length !== this.selectedItemIds.size && selectAllCheckbox.checked === true) { + } else if (selectableItems.length !== this.selectedItemIds.size && selectAllCheckbox.checked === true) { selectAllCheckbox.checked = false; } } diff --git a/app/static/js/ResourceLists/DetailledPublicCorpusList.js b/app/static/js/ResourceLists/DetailledPublicCorpusList.js new file mode 100644 index 00000000..5bfc59ff --- /dev/null +++ b/app/static/js/ResourceLists/DetailledPublicCorpusList.js @@ -0,0 +1,71 @@ +class DetailledPublicCorpusList extends CorpusList { + get item() { + return (values) => { + return ` + <tr class="list-item clickable hoverable"> + <td></td> + <td><b class="title"></b><br><i class="description"></i></td> + <td><span class="owner"></span></td> + <td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td> + <td>${values['current-user-is-following'] ? '<span><i class="left material-icons">visibility</i>Following</span>' : ''}</td> + <td class="right-align"> + <a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a> + </td> + </tr> + `.trim(); + }; + } + + get valueNames() { + return [ + {data: ['id']}, + {data: ['creation-date']}, + {name: 'status', attr: 'data-status'}, + 'description', + 'title', + 'owner', + 'current-user-is-following' + ]; + } + + initListContainerElement() { + if (!this.listContainerElement.hasAttribute('id')) { + this.listContainerElement.id = Utils.generateElementId('corpus-list-'); + } + let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`); + this.listContainerElement.innerHTML = ` + <div class="input-field"> + <i class="material-icons prefix">search</i> + <input id="${listSearchElementId}" class="search" type="text"></input> + <label for="${listSearchElementId}">Search Corpus</label> + </div> + <table> + <thead> + <tr> + <th></th> + <th>Title and Description</th> + <th>Owner</th> + <th>Status</th> + <th></th> + <th></th> + </tr> + </thead> + <tbody class="list"></tbody> + </table> + <ul class="pagination"></ul> + `.trim(); + } + + mapResourceToValue(corpus) { + return { + 'id': corpus.id, + 'creation-date': corpus.creation_date, + 'description': corpus.description, + 'status': corpus.status, + 'title': corpus.title, + 'owner': corpus.user.username, + 'is-owner': corpus.user.id === this.userId, + 'current-user-is-following': Object.values(corpus.corpus_follower_associations).some(association => association.follower.id === currentUserId) + }; + } +} diff --git a/app/static/js/ResourceLists/PublicCorpusList.js b/app/static/js/ResourceLists/PublicCorpusList.js index 4b5f5ecb..ce2c9cbd 100644 --- a/app/static/js/ResourceLists/PublicCorpusList.js +++ b/app/static/js/ResourceLists/PublicCorpusList.js @@ -1,14 +1,17 @@ class PublicCorpusList extends CorpusList { get item() { - return ` - <tr class="list-item clickable hoverable"> - <td><b class="title"></b><br><i class="description"></i></td> - <td><span class="owner"></span></td> - <td class="right-align"> - <a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a> - </td> - </tr> - `.trim(); + return (values) => { + return ` + <tr class="list-item clickable hoverable"> + <td><b class="title"></b><br><i class="description"></i></td> + <td><span class="owner"></span></td> + <td>${values['current-user-is-following'] ? '<span><i class="left material-icons">visibility</i></span>' : ''}</td> + <td class="right-align"> + <a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a> + </td> + </tr> + `.trim(); + }; } initListContainerElement() { @@ -28,6 +31,7 @@ class PublicCorpusList extends CorpusList { <th>Title and Description</th> <th>Owner</th> <th></th> + <th></th> </tr> </thead> <tbody class="list"></tbody> diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index f3b18003..88167db7 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -48,7 +48,8 @@ 'js/ResourceLists/TesseractOCRPipelineModelList.js', 'js/ResourceLists/UserList.js', 'js/ResourceLists/AdminUserList.js', - 'js/ResourceLists/CorpusFollowerList.js' + 'js/ResourceLists/CorpusFollowerList.js', + 'js/ResourceLists/DetailledPublicCorpusList.js' %} <script src="{{ ASSET_URL }}"></script> {%- endassets %} diff --git a/app/templates/corpora/public_corpus.html.j2 b/app/templates/corpora/public_corpus.html.j2 index 6ace0f7a..61efca3a 100644 --- a/app/templates/corpora/public_corpus.html.j2 +++ b/app/templates/corpora/public_corpus.html.j2 @@ -270,7 +270,7 @@ publicCorpusFollowerList.add( {% endif %} // #region Build Corpus Request -{% if cfr.has_permission('MANAGE_CORPUS') %} +{% if cfr.has_permission('MANAGE_FILES') %} let followerBuildRequest = document.querySelector('#follower-build-request'); followerBuildRequest.addEventListener('click', () => { Requests.corpora.entity.build({{ corpus.hashid|tojson }}) diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2 index 89f9121d..7c36ff3a 100644 --- a/app/templates/main/dashboard.html.j2 +++ b/app/templates/main/dashboard.html.j2 @@ -143,7 +143,7 @@ corpusList.add( [ {% for corpus in corpora %} - {{ corpus.to_json_serializeable(backrefs=True)|tojson }}, + {{ corpus.to_json_serializeable(backrefs=True, relationships=True)|tojson }}, {% endfor %} ] ); diff --git a/app/templates/main/social_area.html.j2 b/app/templates/main/social_area.html.j2 index ff57d371..8b8528fc 100644 --- a/app/templates/main/social_area.html.j2 +++ b/app/templates/main/social_area.html.j2 @@ -70,11 +70,11 @@ {% endfor %} ] ); - let publicCorpusList = new PublicCorpusList(document.querySelector('.public-corpus-list')); + let publicCorpusList = new DetailledPublicCorpusList(document.querySelector('.public-corpus-list')); publicCorpusList.add( [ {% for corpus in corpora %} - {{ corpus.to_json_serializeable(backrefs=True)|tojson }}, + {{ corpus.to_json_serializeable(backrefs=True, relationships=True)|tojson }}, {% endfor %} ] ); diff --git a/app/templates/users/user.html.j2 b/app/templates/users/user.html.j2 index 238edd7e..d75ffc7e 100644 --- a/app/templates/users/user.html.j2 +++ b/app/templates/users/user.html.j2 @@ -127,7 +127,7 @@ followedCorpusList.add( [ {% for corpus in user.followed_corpora %} {% if (corpus.is_public or corpus.user == current_user or user == current_user or current_user.is_following_corpus(corpus)) %} - {{ corpus.to_json_serializeable(backrefs=True)|tojson }}, + {{ corpus.to_json_serializeable(backrefs=True, relationships=True)|tojson }}, {% endif %} {% endfor %} ] @@ -137,7 +137,7 @@ publicCorpusList.add( [ {% for corpus in user.corpora %} {% if corpus.is_public %} - {{ corpus.to_json_serializeable(backrefs=True)|tojson }}, + {{ corpus.to_json_serializeable(backrefs=True, relationships=True)|tojson }}, {% endif %} {% endfor %} ] -- GitLab