diff --git a/swh/web/assets/src/bundles/admin/origin-save.js b/swh/web/assets/src/bundles/admin/origin-save.js index b595fe0b..16a21cd4 100644 --- a/swh/web/assets/src/bundles/admin/origin-save.js +++ b/swh/web/assets/src/bundles/admin/origin-save.js @@ -1,313 +1,315 @@ /** * Copyright (C) 2018-2019 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ import {handleFetchError, csrfPost} from 'utils/functions'; let authorizedOriginTable; let unauthorizedOriginTable; let pendingSaveRequestsTable; let acceptedSaveRequestsTable; let rejectedSaveRequestsTable; function enableRowSelection(tableSel) { $(`${tableSel} tbody`).on('click', 'tr', function() { if ($(this).hasClass('selected')) { $(this).removeClass('selected'); + $(tableSel).closest('.tab-pane').find('.swh-action-need-selection').prop('disabled', true); } else { $(`${tableSel} tr.selected`).removeClass('selected'); $(this).addClass('selected'); + $(tableSel).closest('.tab-pane').find('.swh-action-need-selection').prop('disabled', false); } }); } export function initOriginSaveAdmin() { $(document).ready(() => { $.fn.dataTable.ext.errMode = 'throw'; authorizedOriginTable = $('#swh-authorized-origin-urls').DataTable({ serverSide: true, ajax: Urls.admin_origin_save_authorized_urls_list(), columns: [{data: 'url', name: 'url'}], scrollY: '50vh', scrollCollapse: true, info: false }); enableRowSelection('#swh-authorized-origin-urls'); unauthorizedOriginTable = $('#swh-unauthorized-origin-urls').DataTable({ serverSide: true, ajax: Urls.admin_origin_save_unauthorized_urls_list(), columns: [{data: 'url', name: 'url'}], scrollY: '50vh', scrollCollapse: true, info: false }); enableRowSelection('#swh-unauthorized-origin-urls'); let columnsData = [ { data: 'id', name: 'id', visible: false, searchable: false }, { data: 'save_request_date', name: 'request_date', render: (data, type, row) => { if (type === 'display') { let date = new Date(data); return date.toLocaleString(); } return data; } }, { data: 'origin_type', name: 'origin_type' }, { data: 'origin_url', name: 'origin_url', render: (data, type, row) => { if (type === 'display') { const sanitizedURL = $.fn.dataTable.render.text().display(data); return `<a href="${sanitizedURL}">${sanitizedURL}</a>`; } return data; } } ]; pendingSaveRequestsTable = $('#swh-origin-save-pending-requests').DataTable({ serverSide: true, ajax: Urls.origin_save_requests_list('pending'), searchDelay: 1000, columns: columnsData, scrollY: '50vh', scrollCollapse: true, order: [[0, 'desc']], responsive: { details: { type: 'none' } } }); enableRowSelection('#swh-origin-save-pending-requests'); rejectedSaveRequestsTable = $('#swh-origin-save-rejected-requests').DataTable({ serverSide: true, ajax: Urls.origin_save_requests_list('rejected'), searchDelay: 1000, columns: columnsData, scrollY: '50vh', scrollCollapse: true, order: [[0, 'desc']], responsive: { details: { type: 'none' } } }); enableRowSelection('#swh-origin-save-rejected-requests'); columnsData.push({ data: 'save_task_status', name: 'save_task_status', render: (data, type, row) => { if (data === 'succeed') { let browseOriginUrl = Urls.browse_origin(row.origin_url); return `<a href="${browseOriginUrl}">${data}</a>`; } return data; } }); acceptedSaveRequestsTable = $('#swh-origin-save-accepted-requests').DataTable({ serverSide: true, ajax: Urls.origin_save_requests_list('accepted'), searchDelay: 1000, columns: columnsData, scrollY: '50vh', scrollCollapse: true, order: [[0, 'desc']], responsive: { details: { type: 'none' } } }); enableRowSelection('#swh-origin-save-accepted-requests'); $('#swh-origin-save-requests-nav-item').on('shown.bs.tab', () => { pendingSaveRequestsTable.draw(); }); $('#swh-origin-save-url-filters-nav-item').on('shown.bs.tab', () => { authorizedOriginTable.draw(); }); $('#swh-authorized-origins-tab').on('shown.bs.tab', () => { authorizedOriginTable.draw(); }); $('#swh-unauthorized-origins-tab').on('shown.bs.tab', () => { unauthorizedOriginTable.draw(); }); $('#swh-save-requests-pending-tab').on('shown.bs.tab', () => { pendingSaveRequestsTable.draw(); }); $('#swh-save-requests-accepted-tab').on('shown.bs.tab', () => { acceptedSaveRequestsTable.draw(); }); $('#swh-save-requests-rejected-tab').on('shown.bs.tab', () => { rejectedSaveRequestsTable.draw(); }); $('#swh-save-requests-pending-tab').click(() => { pendingSaveRequestsTable.ajax.reload(null, false); }); $('#swh-save-requests-accepted-tab').click(() => { acceptedSaveRequestsTable.ajax.reload(null, false); }); $('#swh-save-requests-rejected-tab').click(() => { rejectedSaveRequestsTable.ajax.reload(null, false); }); }); } export function addAuthorizedOriginUrl() { let originUrl = $('#swh-authorized-url-prefix').val(); let addOriginUrl = Urls.admin_origin_save_add_authorized_url(originUrl); csrfPost(addOriginUrl) .then(handleFetchError) .then(() => { authorizedOriginTable.row.add({'url': originUrl}).draw(); }) .catch(response => { swh.webapp.showModalMessage( 'Duplicated origin url prefix', 'The provided origin url prefix is already registered in the authorized list.'); }); } export function removeAuthorizedOriginUrl() { let originUrl = $('#swh-authorized-origin-urls tr.selected').text(); if (originUrl) { let removeOriginUrl = Urls.admin_origin_save_remove_authorized_url(originUrl); csrfPost(removeOriginUrl) .then(handleFetchError) .then(() => { authorizedOriginTable.row('.selected').remove().draw(); }) .catch(() => {}); } } export function addUnauthorizedOriginUrl() { let originUrl = $('#swh-unauthorized-url-prefix').val(); let addOriginUrl = Urls.admin_origin_save_add_unauthorized_url(originUrl); csrfPost(addOriginUrl) .then(handleFetchError) .then(() => { unauthorizedOriginTable.row.add({'url': originUrl}).draw(); }) .catch(() => { swh.webapp.showModalMessage( 'Duplicated origin url prefix', 'The provided origin url prefix is already registered in the unauthorized list.'); }); } export function removeUnauthorizedOriginUrl() { let originUrl = $('#swh-unauthorized-origin-urls tr.selected').text(); if (originUrl) { let removeOriginUrl = Urls.admin_origin_save_remove_unauthorized_url(originUrl); csrfPost(removeOriginUrl) .then(handleFetchError) .then(() => { unauthorizedOriginTable.row('.selected').remove().draw(); }) .catch(() => {}); } } export function acceptOriginSaveRequest() { let selectedRow = pendingSaveRequestsTable.row('.selected'); if (selectedRow.length) { let acceptOriginSaveRequestCallback = () => { let rowData = selectedRow.data(); let acceptSaveRequestUrl = Urls.admin_origin_save_request_accept(rowData['origin_type'], rowData['origin_url']); csrfPost(acceptSaveRequestUrl) .then(() => { pendingSaveRequestsTable.ajax.reload(null, false); }); }; swh.webapp.showModalConfirm( 'Accept origin save request ?', 'Are you sure to accept this origin save request ?', acceptOriginSaveRequestCallback); } } export function rejectOriginSaveRequest() { let selectedRow = pendingSaveRequestsTable.row('.selected'); if (selectedRow.length) { let rejectOriginSaveRequestCallback = () => { let rowData = selectedRow.data(); let rejectSaveRequestUrl = Urls.admin_origin_save_request_reject(rowData['origin_type'], rowData['origin_url']); csrfPost(rejectSaveRequestUrl) .then(() => { pendingSaveRequestsTable.ajax.reload(null, false); }); }; swh.webapp.showModalConfirm( 'Reject origin save request ?', 'Are you sure to reject this origin save request ?', rejectOriginSaveRequestCallback); } } function removeOriginSaveRequest(requestTable) { let selectedRow = requestTable.row('.selected'); if (selectedRow.length) { let requestId = selectedRow.data()['id']; let removeOriginSaveRequestCallback = () => { let removeSaveRequestUrl = Urls.admin_origin_save_request_remove(requestId); csrfPost(removeSaveRequestUrl) .then(() => { requestTable.ajax.reload(null, false); }); }; swh.webapp.showModalConfirm( 'Remove origin save request ?', 'Are you sure to remove this origin save request ?', removeOriginSaveRequestCallback); } } export function removePendingOriginSaveRequest() { removeOriginSaveRequest(pendingSaveRequestsTable); } export function removeAcceptedOriginSaveRequest() { removeOriginSaveRequest(acceptedSaveRequestsTable); } export function removeRejectedOriginSaveRequest() { removeOriginSaveRequest(rejectedSaveRequestsTable); } diff --git a/swh/web/templates/admin/origin-save.html b/swh/web/templates/admin/origin-save.html index e25d13aa..d32f8b8c 100644 --- a/swh/web/templates/admin/origin-save.html +++ b/swh/web/templates/admin/origin-save.html @@ -1,179 +1,179 @@ {% extends "layout.html" %} {% comment %} Copyright (C) 2018-2019 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load swh_templatetags %} {% load render_bundle from webpack_loader %} {% block header %} {{ block.super }} {% render_bundle 'admin' %} {% endblock %} {% block title %} Save origin administration {% endblock %} {% block navbar-content %} <h4>Save origin administration</h4> {% endblock %} {% block content %} <ul class="nav nav-tabs" style="padding-left: 5px;"> <li class="nav-item"><a class="nav-link active" data-toggle="tab" id="swh-origin-save-requests-nav-item" href="#swh-origin-save-requests">Submitted save origin requests</a></li> <li class="nav-item"><a class="nav-link" data-toggle="tab" id="swh-origin-save-url-filters-nav-item" href="#swh-origin-save-url-filters">Origin urls filtering</a></li> </ul> <div class="tab-content"> <div id="swh-origin-save-requests" class="tab-pane active"> <ul class="nav nav-pills mt-3 mb-3" role="tablist"> <li class="nav-item"> <a class="nav-link active" id="swh-save-requests-pending-tab" data-toggle="pill" href="#swh-save-requests-pending" role="tab" aria-controls="swh-save-requests-pending" aria-selected="true">Pending</a> </li> <li class="nav-item"> <a class="nav-link" id="swh-save-requests-accepted-tab" data-toggle="pill" href="#swh-save-requests-accepted" role="tab" aria-controls="swh-save-requests-accepted" aria-selected="false">Accepted</a> </li> <li class="nav-item"> <a class="nav-link" id="swh-save-requests-rejected-tab" data-toggle="pill" href="#swh-save-requests-rejected" role="tab" aria-controls="swh-save-requests-rejected" aria-selected="false">Rejected</a> </li> </ul> <div class="tab-content"> <div class="tab-pane fade show active" id="swh-save-requests-pending" role="tabpanel" aria-labelledby="swh-save-requests-pending-tab"> <table id="swh-origin-save-pending-requests" class="table swh-table swh-table-striped" width="100%"> <thead> <tr> <th></th> <th data-priority="2">Date</th> <th data-priority="3">Type</th> <th data-priority="1">Url</th> </tr> </thead> </table> <div class="row text-right mt-3"> <div class="col-md-6"> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.acceptOriginSaveRequest()">Accept selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.acceptOriginSaveRequest()" disabled>Accept selected</button> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.rejectOriginSaveRequest()">Reject selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.rejectOriginSaveRequest()" disabled>Reject selected</button> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.removePendingOriginSaveRequest()">Remove selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.removePendingOriginSaveRequest()" disabled>Remove selected</button> </div> </div> </div> <div class="tab-pane fade" id="swh-save-requests-accepted" role="tabpanel" aria-labelledby="swh-save-requests-accepted-tab"> <table id="swh-origin-save-accepted-requests" class="table swh-table swh-table-striped" width="100%"> <thead> <tr> <th></th> <th data-priority="3">Date</th> <th data-priority="4">Type</th> <th data-priority="1">Url</th> <th data-priority="2">Status</th> </tr> </thead> </table> <div class="row text-right mt-3"> <div class="col-md-10"> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.removeAcceptedOriginSaveRequest()">Remove selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.removeAcceptedOriginSaveRequest()" disabled>Remove selected</button> </div> </div> </div> <div class="tab-pane fade" id="swh-save-requests-rejected" role="tabpanel" aria-labelledby="swh-save-requests-rejected-tab"> <table id="swh-origin-save-rejected-requests" class="table swh-table swh-table-striped" width="100%"> <thead> <tr> <th></th> <th data-priority="2">Date</th> <th data-priority="3">Type</th> <th data-priority="1">Url</th> </tr> </thead> </table> <div class="row text-right mt-3"> <div class="col-md-10"> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.removeRejectedOriginSaveRequest()">Remove selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.removeRejectedOriginSaveRequest()" disabled>Remove selected</button> </div> </div> </div> </div> </div> <div id="swh-origin-save-url-filters" class="tab-pane"> <ul class="nav nav-pills mt-3 mb-3" role="tablist"> <li class="nav-item"> <a class="nav-link active" id="swh-authorized-origins-tab" data-toggle="pill" href="#swh-authorized-origins" role="tab" aria-controls="swh-authorized-origins" aria-selected="true">Authorized urls</a> </li> <li class="nav-item"> <a class="nav-link" id="swh-unauthorized-origins-tab" data-toggle="pill" href="#swh-unauthorized-origins" role="tab" aria-controls="swh-unauthorized-origins" aria-selected="false">Unauthorized urls</a> </li> </ul> <div class="tab-content"> <div class="tab-pane fade show active" id="swh-authorized-origins" role="tabpanel" aria-labelledby="swh-authorized-origins-tab"> <table id="swh-authorized-origin-urls" class="table swh-table swh-table-striped" width="100%"> <thead> <tr> <th>Url</th> </tr> </thead> </table> <div class="row text-right mt-3"> <div class="col-md-10"> <div class="input-group"> <input class="form-control" placeholder="Enter authorized origin url prefix to add" type="text" id="swh-authorized-url-prefix"/> <div class="input-group-append"> <button class="btn btn-default" onclick="swh.admin.addAuthorizedOriginUrl()">Add new</button> </div> </div> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.removeAuthorizedOriginUrl()">Remove selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.removeAuthorizedOriginUrl()" disabled>Remove selected</button> </div> </div> </div> <div class="tab-pane fade" id="swh-unauthorized-origins" role="tabpanel" aria-labelledby="swh-unauthorized-origins-tab"> <table id="swh-unauthorized-origin-urls" class="table swh-table swh-table-striped" width="100%"> <thead> <tr> <th>Url</th> </tr> </thead> </table> <div class="row text-right mt-3"> <div class="col-md-10"> <div class="input-group"> <input class="form-control" placeholder="Enter unauthorized origin url prefix to add" type="text" id="swh-unauthorized-url-prefix"/> <div class="input-group-append"> <button class="btn btn-default" onclick="swh.admin.addUnauthorizedOriginUrl()">Add new</button> </div> </div> </div> <div class="col-md-2"> - <button class="btn btn-default" onclick="swh.admin.removeUnauthorizedOriginUrl()">Remove selected</button> + <button class="btn btn-default swh-action-need-selection" onclick="swh.admin.removeUnauthorizedOriginUrl()" disabled>Remove selected</button> </div> </div> </div> </div> </div> </div> <script> swh.webapp.initPage('origin-save-admin'); swh.admin.initOriginSaveAdmin(); </script> {% endblock %}