diff --git a/swh/web/assets/src/bundles/browse/origin-search.js b/swh/web/assets/src/bundles/browse/origin-search.js index f4ad89444..e3fdbf370 100644 --- a/swh/web/assets/src/bundles/browse/origin-search.js +++ b/swh/web/assets/src/bundles/browse/origin-search.js @@ -1,164 +1,193 @@ /** * Copyright (C) 2018 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 {heapsPermute} from 'utils/heaps-permute'; import {handleFetchError} from 'utils/functions'; let originPatterns; let perPage = 20; let limit = perPage * 10; let offset = 0; let currentData = null; let inSearch = false; function fixTableRowsStyle() { setTimeout(() => { $('#origin-search-results tbody tr').removeAttr('style'); }); } function clearOriginSearchResultsTable() { $('#origin-search-results tbody tr').remove(); } function populateOriginSearchResultsTable(data, offset) { let localOffset = offset % limit; if (data.length > 0) { $('#swh-origin-search-results').show(); - $('#swh-no-origins-found').hide(); + $('#swh-no-result').hide(); clearOriginSearchResultsTable(); let table = $('#origin-search-results tbody'); for (let i = localOffset; i < localOffset + perPage && i < data.length; ++i) { let elem = data[i]; let tableRow = ''; tableRow += '' + elem.type + ''; let browseUrl = Urls.browse_origin(elem.url); tableRow += '' + browseUrl + ''; tableRow += ''; tableRow += ''; table.append(tableRow); // get async latest visit snapshot and update visit status icon let latestSnapshotUrl = Urls.browse_origin_latest_snapshot(elem.id); fetch(latestSnapshotUrl, {credentials: 'same-origin'}) .then(response => response.json()) .then(data => { let originId = elem.id; $('#visit-status-origin-' + originId).children().remove(); if (data) { $('#visit-status-origin-' + originId).append(''); } else { $('#visit-status-origin-' + originId).append(''); } }); } fixTableRowsStyle(); } else { $('#swh-origin-search-results').hide(); - $('#swh-no-origins-found').show(); + $('#swh-no-result').text('No origins matching the search criteria were found.'); + $('#swh-no-result').show(); } if (data.length - localOffset < perPage || (data.length < limit && (localOffset + perPage) === data.length)) { $('#origins-next-results-button').addClass('disabled'); } else { $('#origins-next-results-button').removeClass('disabled'); } if (offset > 0) { $('#origins-prev-results-button').removeClass('disabled'); } else { $('#origins-prev-results-button').addClass('disabled'); } inSearch = false; setTimeout(() => { window.scrollTo(0, 0); }); } function searchOrigins(patterns, limit, searchOffset, offset) { originPatterns = patterns; let patternsArray = patterns.trim().replace(/\s+/g, ' ').split(' '); let patternsPermut = []; heapsPermute(patternsArray, p => patternsPermut.push(p.join('.*'))); let regex = patternsPermut.join('|'); let searchUrl = Urls.browse_origin_search(regex) + `?limit=${limit}&offset=${searchOffset}®exp=true`; clearOriginSearchResultsTable(); $('.swh-loading').addClass('show'); fetch(searchUrl, {credentials: 'same-origin'}) .then(handleFetchError) .then(response => response.json()) .then(data => { currentData = data; if (typeof Storage !== 'undefined') { sessionStorage.setItem('last-swh-origin-url-patterns', patterns); sessionStorage.setItem('last-swh-origin-search-results', JSON.stringify(data)); sessionStorage.setItem('last-swh-origin-search-offset', offset); } $('.swh-loading').removeClass('show'); populateOriginSearchResultsTable(data, offset); }) .catch(() => { $('.swh-loading').removeClass('show'); inSearch = false; }); } export function initOriginSearch() { $(document).ready(() => { if (typeof Storage !== 'undefined') { originPatterns = sessionStorage.getItem('last-swh-origin-url-patterns'); let data = sessionStorage.getItem('last-swh-origin-search-results'); offset = sessionStorage.getItem('last-swh-origin-search-offset'); if (data) { $('#origins-url-patterns').val(originPatterns); offset = parseInt(offset); populateOriginSearchResultsTable(JSON.parse(data), offset); } } $('#search_origins').submit(event => { + event.preventDefault(); + $('#swh-no-result').hide(); let patterns = $('#origins-url-patterns').val(); offset = 0; inSearch = true; - searchOrigins(patterns, limit, offset, offset); - event.preventDefault(); + // first try to resolve a swh persistent identifier + let resolvePidUrl = Urls.resolve_swh_pid(patterns); + fetch(resolvePidUrl, {credentials: 'same-origin'}) + .then(handleFetchError) + .then(response => response.json()) + .then(data => { + // pid has been successfully resolved, + // so redirect to browse page + window.location = data.browse_url; + }) + .catch(response => { + // pid resolving failed + if (patterns.startsWith('swh:')) { + // display a useful error message if the input + // looks like a swh pid + response.json().then(data => { + $('#swh-origin-search-results').hide(); + $('.swh-search-pagination').hide(); + $('#swh-no-result').text(data.reason); + $('#swh-no-result').show(); + }); + } else { + // otherwise, proceed with origins search + $('#swh-origin-search-results').show(); + $('.swh-search-pagination').show(); + searchOrigins(patterns, limit, offset, offset); + } + }); }); $('#origins-next-results-button').click(event => { if ($('#origins-next-results-button').hasClass('disabled') || inSearch) { return; } inSearch = true; offset += perPage; if (!currentData || offset % limit === 0) { searchOrigins(originPatterns, limit, offset, offset); } else { populateOriginSearchResultsTable(currentData, offset); } event.preventDefault(); }); $('#origins-prev-results-button').click(event => { if ($('#origins-prev-results-button').hasClass('disabled') || inSearch) { return; } inSearch = true; offset -= perPage; if (!currentData || (offset > 0 && (offset + perPage) % limit === 0)) { searchOrigins(originPatterns, limit, (offset + perPage) - limit, offset); } else { populateOriginSearchResultsTable(currentData, offset); } event.preventDefault(); }); $(document).on('shown.bs.tab', 'a[data-toggle="tab"]', e => { if (e.currentTarget.text.trim() === 'Search') { fixTableRowsStyle(); } }); }); } diff --git a/swh/web/assets/src/utils/functions.js b/swh/web/assets/src/utils/functions.js index 79d92a70a..a56a91dae 100644 --- a/swh/web/assets/src/utils/functions.js +++ b/swh/web/assets/src/utils/functions.js @@ -1,28 +1,28 @@ /** * Copyright (C) 2018 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 */ // utility functions export function handleFetchError(response) { if (!response.ok) { - throw Error(response.statusText); + throw response; } return response; } export function handleFetchErrors(responses) { for (let i = 0; i < responses.length; ++i) { if (!responses[i].ok) { - throw Error(responses[i].statusText); + throw responses[i]; } } return responses; } export function staticAsset(asset) { return `${__STATIC__}${asset}`; } diff --git a/swh/web/templates/browse-search.html b/swh/web/templates/browse-search.html index 4053adcc3..fc6b52ce3 100644 --- a/swh/web/templates/browse-search.html +++ b/swh/web/templates/browse-search.html @@ -1,61 +1,61 @@ {% extends "browse-layout.html" %} {% comment %} Copyright (C) 2017-2018 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 static %} {% block navbar-content %}

Search software origins to browse

{% endblock %} {% block browse-content %}
- +

Searching origins ...

- {% endblock %} \ No newline at end of file