diff --git a/cypress/integration/deposit-admin.spec.js b/cypress/integration/deposit-admin.spec.js --- a/cypress/integration/deposit-admin.spec.js +++ b/cypress/integration/deposit-admin.spec.js @@ -17,51 +17,78 @@ .submit(); } -describe('Test admin deposit page', function() { - it('Should test deposit page', function() { - cy.visit(this.Urls.admin_deposit()); - // FIXME: cypress anti-pattern, do not use ui to log ¯\_(ツ)_/¯ - // https://docs.cypress.io/guides/getting-started/testing-your-app.html#Logging-in - login(username, password); +// data to use as request query response +let responseDeposits; - cy.server(); - let inputDeposits = [ +describe('Test admin deposit page', function() { + beforeEach(() => { + responseDeposits = [ { 'id': 614, - 'external_id': 'c-d-1', + 'external_id': 'ch-de-1', 'reception_date': '2020-05-18T13:48:27Z', 'status': 'done', - 'status_detail': 'all good', + 'status_detail': null, 'swh_id': 'swh:1:dir:ef04a768', 'swh_id_context': 'swh:1:dir:ef04a768;origin=https://w.s.o/c-d-1;visit=swh:1:snp:b234be1e;anchor=swh:1:rev:d24a75c9;path=/' }, { 'id': 613, - 'external_id': 'c-d-2', + 'external_id': 'ch-de-2', 'reception_date': '2020-05-18T11:20:16Z', 'status': 'done', - 'status_detail': 'everything is fine', + 'status_detail': null, 'swh_id': 'swh:1:dir:181417fb', 'swh_id_context': 'swh:1:dir:181417fb;origin=https://w.s.o/c-d-2;visit=swh:1:snp:8c32a2ef;anchor=swh:1:rev:3d1eba04;path=/' }, { 'id': 612, - 'external_id': 'c-d-3', + 'external_id': 'ch-de-3', 'reception_date': '2020-05-18T11:20:16Z', 'status': 'rejected', - 'status_detail': 'hu ho, issue!', + 'status_detail': 'incomplete deposit!', 'swh_id': null, 'swh_id_context': null } ]; + }); + + it('Should filter out deposits matching excluding pattern from display', function() { + cy.visit(this.Urls.admin_deposit()); + // FIXME: cypress anti-pattern, do not use ui to log ¯\_(ツ)_/¯ + // https://docs.cypress.io/guides/getting-started/testing-your-app.html#Logging-in + login(username, password); + + cy.server(); + + // entry supposed to be excluded from the display by default + let extraDeposit = { + 'id': 10, + 'external_id': 'check-deposit-3', + 'reception_date': '2020-05-18T11:20:16Z', + 'status': 'done', + 'status_detail': null, + 'swh_id': 'swh:1:dir:fb234417', + 'swh_id_context': 'swh:1:dir:fb234417;origin=https://w.s.o/c-d-3;visit=swh:1:snp:181417fb;anchor=swh:1:rev:3d166604;path=/' + }; + + // of course, that's how to copy a list (an "array") + let testDeposits = responseDeposits.slice(); + // and add a new element to that array by mutating it... + testDeposits.push(extraDeposit); + + // ensure we don't touch the original reference + expect(responseDeposits.length).to.be.equal(3); + expect(testDeposits.length).to.be.equal(4); + cy.route({ method: 'GET', url: `${this.Urls.admin_deposit_list()}**`, response: { 'draw': 10, - 'recordsTotal': 3, - 'recordsFiltered': 3, - 'data': inputDeposits + 'recordsTotal': testDeposits.length, + 'recordsFiltered': testDeposits.length, + 'data': testDeposits } }).as('listDeposits'); @@ -73,74 +100,217 @@ .should('exist'); // those are computed from the - let expectedOrigins = ['https://w.s.o/c-d-1', 'https://w.s.o/c-d-2', '']; + let expectedOrigins = [ + 'https://w.s.o/c-d-1', 'https://w.s.o/c-d-2', '', 'https://w.s.o/c-d-3' + ]; cy.wait('@listDeposits').then((xhr) => { - cy.log('response:', xhr.response); - cy.log(xhr.response.body); let deposits = xhr.response.body.data; - cy.log('Deposits: ', deposits); - expect(deposits.length).to.equal(inputDeposits.length); + expect(deposits.length).to.equal(testDeposits.length); cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows'); // only 2 entries cy.get('@rows').each((row, idx, collection) => { let deposit = deposits[idx]; - let inputDeposit = inputDeposits[idx]; - assert.isNotNull(deposit); - assert.isNotNull(inputDeposit); - expect(deposit.id).to.be.equal(inputDeposit['id']); - expect(deposit.external_id).to.be.equal(inputDeposit['external_id']); - expect(deposit.status).to.be.equal(inputDeposit['status']); - expect(deposit.status_detail).to.be.equal(inputDeposit['status_detail']); - expect(deposit.swh_id).to.be.equal(inputDeposit['swh_id']); - expect(deposit.swh_id_context).to.be.equal(inputDeposit['swh_id_context']); + let responseDeposit = testDeposits[idx]; + cy.log('deposit', deposit); + cy.log('responseDeposit', responseDeposit); + expect(deposit.id).to.be.equal(responseDeposit['id']); + expect(deposit.external_id).to.be.equal(responseDeposit['external_id']); + expect(deposit.status).to.be.equal(responseDeposit['status']); + expect(deposit.status_detail).to.be.equal(responseDeposit['status_detail']); + expect(deposit.swh_id).to.be.equal(responseDeposit['swh_id']); + expect(deposit.swh_id_context).to.be.equal(responseDeposit['swh_id_context']); let expectedOrigin = expectedOrigins[idx]; - // ensure it's in the dom - expect(row).to.contain(deposit.id); - if (deposit.status === 'done') { - expect(row).to.contain(deposit.external_id); - } else { - expect(row).to.not.contain(deposit.external_id); - } - expect(row).to.contain(deposit.status); - expect(row).to.contain(expectedOrigin); - // those are hidden by default - expect(row).to.not.contain(deposit.status_detail); - expect(row).to.not.contain(deposit.swh_id); - expect(row).to.not.contain(deposit.swh_id_context); - }); - // toggling all links and ensure, the previous checks are inverted - cy.get('a.toggle-col').click({'multiple': true}).then(() => { - - cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows'); - cy.get('@rows').each((row, idx, collection) => { - let deposit = deposits[idx]; - - // ensure it's in the dom - expect(row).to.not.contain(deposit.id); - if (deposit.status === 'done') { - expect(row).to.contain(deposit.external_id); - } else { - expect(row).to.not.contain(deposit.external_id); + // part of the data, but it should not be displayed (got filtered out) + if (deposit.external_id === 'check-deposit-3') { + cy.contains(deposit.status).should('not.be.visible'); + cy.contains(deposit.status_detail).should('not.be.visible'); + cy.contains(deposit.external_id).should('not.be.visible'); + cy.contains(expectedOrigin).should('not.be.visible'); + cy.contains(deposit.swh_id).should('not.be.visible'); + cy.contains(deposit.swh_id_context).should('not.be.visible'); + } else { + expect(deposit.external_id).to.be.not.equal('check-deposit-3'); + cy.contains(deposit.id).should('be.visible'); + if (deposit.status !== 'rejected') { + cy.contains(deposit.external_id).should('not.be.visible'); + cy.contains(expectedOrigin).should('be.visible'); + // ensure it's in the dom } - expect(row).to.not.contain(deposit.status); + cy.contains(deposit.status).should('be.visible'); + // those are hidden by default, so now visible + if (deposit.status_detail !== null) { + cy.contains(deposit.status_detail).should('not.be.visible'); + } + // those are hidden by default - expect(row).to.contain(deposit.status_detail); if (deposit.swh_id !== null) { - expect(row).to.contain(deposit.swh_id); - expect(row).to.contain(deposit.swh_id_context); + cy.contains(deposit.swh_id).should('not.be.visible'); + cy.contains(deposit.swh_id_context).should('not.be.visible'); } - }); - + } }); - cy.get('#swh-admin-deposit-list-error') - .should('not.contain', - 'An error occurred while retrieving the list of deposits'); + // toggling all links and ensure, the previous checks are inverted + // cy.get('a.toggle-col').click({'multiple': true}).then(() => { + // cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows'); + + // cy.get('@rows').should('have.length', 3); + + // cy.get('@rows').each((row, idx, collection) => { + // let deposit = deposits[idx]; + // let expectedOrigin = expectedOrigins[idx]; + + // if (deposit.external_id === 'check-deposit-3') { // filtered out deposit + // cy.contains(deposit.status).should('not.be.visible'); + // cy.contains(deposit.status_detail).should('not.be.visible'); + // cy.contains(deposit.external_id).should('not.be.visible'); + // cy.contains(expectedOrigin).should('not.be.visible'); + // cy.contains(deposit.swh_id).should('not.be.visible'); + // cy.contains(deposit.swh_id_context).should('not.be.visible'); + // } else { + // expect(deposit.external_id).to.be.not.equal('check-deposit-3'); + // // ensure it's in the dom + // cy.contains(deposit.id).should('not.be.visible'); + // if (deposit.status !== 'rejected') { + // cy.contains(deposit.external_id).should('not.be.visible'); + // expect(row).to.contain(expectedOrigin); + // } + + // expect(row).to.not.contain(deposit.status); + // // those are hidden by default, so now visible + // if (deposit.status_detail !== null) { + // cy.contains(deposit.status_detail).should('be.visible'); + // } + + // // those are hidden by default, so now they should be visible + // if (deposit.swh_id !== null) { + // cy.contains(deposit.swh_id).should('be.visible'); + // cy.contains(deposit.swh_id_context).should('be.visible'); + // } + // } + // }); + // }); + + // cy.get('#swh-admin-deposit-list-error') + // .should('not.contain', + // 'An error occurred while retrieving the list of deposits'); }); + }); + + // it('Should display properly entries', function() { + // cy.visit(this.Urls.admin_deposit()); + // // FIXME: cypress anti-pattern, do not use ui to log ¯\_(ツ)_/¯ + // // https://docs.cypress.io/guides/getting-started/testing-your-app.html#Logging-in + // login(username, password); + + // let testDeposits = responseDeposits; + + // cy.server(); + // cy.route({ + // method: 'GET', + // url: `${this.Urls.admin_deposit_list()}**`, + // response: { + // 'draw': 10, + // 'recordsTotal': testDeposits.length, + // 'recordsFiltered': testDeposits.length, + // 'data': testDeposits + // } + // }).as('listDeposits'); + + // cy.location('pathname') + // .should('be.equal', this.Urls.admin_deposit()); + // cy.url().should('include', '/admin/deposit'); + + // cy.get('#swh-admin-deposit-list') + // .should('exist'); + + // // those are computed from the + // let expectedOrigins = [ + // 'https://w.s.o/c-d-1', 'https://w.s.o/c-d-2', '' + // ]; + + // cy.wait('@listDeposits').then((xhr) => { + // cy.log('response:', xhr.response); + // cy.log(xhr.response.body); + // let deposits = xhr.response.body.data; + // cy.log('Deposits: ', deposits); + // expect(deposits.length).to.equal(testDeposits.length); + + // cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows'); + + // // only 2 entries + // cy.get('@rows').each((row, idx, collection) => { + // let deposit = deposits[idx]; + // let responseDeposit = testDeposits[idx]; + // assert.isNotNull(deposit); + // assert.isNotNull(responseDeposit); + // expect(deposit.id).to.be.equal(responseDeposit['id']); + // expect(deposit.external_id).to.be.equal(responseDeposit['external_id']); + // expect(deposit.status).to.be.equal(responseDeposit['status']); + // expect(deposit.status_detail).to.be.equal(responseDeposit['status_detail']); + // expect(deposit.swh_id).to.be.equal(responseDeposit['swh_id']); + // expect(deposit.swh_id_context).to.be.equal(responseDeposit['swh_id_context']); + + // let expectedOrigin = expectedOrigins[idx]; + // // ensure it's in the dom + // cy.contains(deposit.id).should('be.visible'); + // if (deposit.status !== 'rejected') { + // expect(row).to.not.contain(deposit.external_id); + // cy.contains(expectedOrigin).should('be.visible'); + // } + + // cy.contains(deposit.status).should('be.visible'); + // // those are hidden by default, so now visible + // if (deposit.status_detail !== null) { + // cy.contains(deposit.status_detail).should('not.be.visible'); + // } + + // // those are hidden by default + // if (deposit.swh_id !== null) { + // cy.contains(deposit.swh_id).should('not.be.visible'); + // cy.contains(deposit.swh_id_context).should('not.be.visible'); + // } + // }); + + // // toggling all links and ensure, the previous checks are inverted + // cy.get('a.toggle-col').click({'multiple': true}).then(() => { + // cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows'); + + // cy.get('@rows').each((row, idx, collection) => { + // let deposit = deposits[idx]; + // let expectedOrigin = expectedOrigins[idx]; + + // // ensure it's in the dom + // cy.contains(deposit.id).should('not.be.visible'); + // if (deposit.status !== 'rejected') { + // expect(row).to.not.contain(deposit.external_id); + // expect(row).to.contain(expectedOrigin); + // } + + // expect(row).to.not.contain(deposit.status); + // // those are hidden by default, so now visible + // if (deposit.status_detail !== null) { + // cy.contains(deposit.status_detail).should('be.visible'); + // } + + // // those are hidden by default, so now they should be visible + // if (deposit.swh_id !== null) { + // cy.contains(deposit.swh_id).should('be.visible'); + // cy.contains(deposit.swh_id_context).should('be.visible'); + // } + // }); + // }); + + // cy.get('#swh-admin-deposit-list-error') + // .should('not.contain', + // 'An error occurred while retrieving the list of deposits'); + // }); + + // }); }); diff --git a/swh/web/assets/src/bundles/admin/deposit.js b/swh/web/assets/src/bundles/admin/deposit.js --- a/swh/web/assets/src/bundles/admin/deposit.js +++ b/swh/web/assets/src/bundles/admin/deposit.js @@ -15,17 +15,111 @@ return data; } +function swhPatternMatch(string, pattern) { + /** Check if a string match a given pattern. + * Return true if it matches, false otherwise. */ + return (typeof string === 'string' || string instanceof String) && + string.search(pattern) !== -1; +} + +function filterDataWithExcludePattern(data, excludePattern) { + /** Return true if the data is to be filtered, false otherwise. */ + // only check the external-id column + return swhPatternMatch(data['external_id'], excludePattern); + // following works but check all columns (slower for large data set i guess) + // for (const key in data) { + // console.log('swh update - key: ', key); + // let value = data[key]; + // console.log('swh update - value: ', value); + // if (swhPatternMatch(value, excludePattern)) { + // return true; // exclude the data from filtering + // } + // } + // return false; +} + +// function dataTableUpdateDataWithoutExcludedPattern(settings, data, dataIndex) { +// // expect data to be a dict +// console.log('swh update - settings', settings); +// console.log('swh update - data index', dataIndex); +// let excludePattern = $('#swh-admin-deposit-list-exclude-filter').val(); +// return !filterDataWithExcludePattern(data, excludePattern); +// } + export function initDepositAdmin() { let depositsTable; $(document).ready(() => { - $.fn.dataTable.ext.errMode = 'none'; + $.fn.dataTable.ext.errMode = 'none'; // none (prod), alert (default), throw + // the following not working, it's supposed to be used by the search mechanism + // but it does not ¯\_(ツ)_/¯... + // including the custom exclude filtering + // $.fn.dataTable.ext.search.push(dataTableUpdateDataWithoutExcludedPattern); depositsTable = $('#swh-admin-deposit-list') .on('error.dt', (e, settings, techNote, message) => { $('#swh-admin-deposit-list-error').text(message); }) .DataTable({ serverSide: true, - ajax: Urls.admin_deposit_list(), + processing: true, + // let's define the order of table options display + // f: (f)ilter + // l: (l)ength changing + // r: p(r)ocessing + // t: (t)able + // i: (i)nfo + // p: (p)agination + // see https://datatables.net/examples/basic_init/dom.html + dom: '<l>rt<"bottom"ip>>', + // list-exclude is a custom filter + // see https://datatables.net/examples/advanced_init/dom_toolbar.html + ajax: { + url: Urls.admin_deposit_list(), + // filtering data set depending on the exclude search input + dataFilter: function(dataResponse) { + // dataResponse: str + let data = jQuery.parseJSON(dataResponse); + console.log('datafilter: data', data); + let excludePattern = $('#swh-admin-deposit-list-exclude-filter').val(); + console.log('datafilter: exclude pattern', excludePattern); + // if (typeof excludePattern === 'undefined') {// unneeded + // console.log('datafilter: exclude pattern undefined, fixing'); + // excludePattern = 'check-deposit'; + // } + let recordsFiltered = 0; + let filteredData = []; + for (const row of data.data) { + console.log('datafilter - filtered data - row:', row); + if (filterDataWithExcludePattern(row, excludePattern)) { + console.log('datafilter - excluding row', row); + recordsFiltered += 1; + } else { + console.log('datafilter - keeping row', row); + filteredData.push(row); + } + } + // update data values + data['recordsFiltered'] = recordsFiltered; + data['data'] = filteredData; + console.log('datafilter out', data); + return JSON.stringify(data); + } + }, + // rowCallback: function(row, data) { + // const api = this.api(); + // let excludePattern = $('#swh-admin-deposit-list-exclude-filter').val(); + // // console.log('row-callback - ', row); + // // console.log('row-callback - ', data); + // for (const key in data) { + // // console.log('row callback - key: ', key); + // let value = data[key]; + // // console.log('row callback - value: ', value); + // if (swhPatternMatch(value, excludePattern)) { + // console.log('row callback, should be removed', key, value); + // api.rows(row).remove().draw(); + // break; + // } + // } + // }, columns: [ { data: 'id', @@ -106,6 +200,30 @@ scrollCollapse: true, order: [[0, 'desc']] }); + + // Some more customization is needed on the table + $('div#list-exclude').html(`
+
+ +
+
+`); + + // Adding exclusion pattern update behavior + $('#swh-admin-deposit-list-exclude-filter').keyup(function() { + depositsTable.draw(); + }); + + // search with current default search so that it uses the excluding pattern + // and then draw + // depositsTable.search(".*", true); depositsTable.draw(); });