diff --git a/ui/cap-react/src/antd/search/Loaders/Results.js b/ui/cap-react/src/antd/search/Loaders/Results.js index 2a75703d39..e7a5538fef 100644 --- a/ui/cap-react/src/antd/search/Loaders/Results.js +++ b/ui/cap-react/src/antd/search/Loaders/Results.js @@ -1,9 +1,9 @@ import { Skeleton } from "antd"; const Results = () => { - return [...Array(5)].map(item => ( + return [...Array(5)].map((_, index) => (
diff --git a/ui/cap-react/src/antd/search/components/Header.js b/ui/cap-react/src/antd/search/components/Header.js index 88200cc1e2..9e962718fd 100644 --- a/ui/cap-react/src/antd/search/components/Header.js +++ b/ui/cap-react/src/antd/search/components/Header.js @@ -1,7 +1,8 @@ import PropTypes from "prop-types"; import queryString from "query-string"; -import { Button, Row, Select, Space, Typography } from "antd"; -import { FilterOutlined } from "@ant-design/icons"; +import { Button, Dropdown, Row, Select, Space, Typography } from "antd"; +import { EllipsisOutlined, FilterOutlined } from "@ant-design/icons"; +import { DRAFTS, PUBLISHED } from "../../routes"; const SORT_OPTIONS = [ { value: "mostrecent", label: "Newest First" }, @@ -9,6 +10,17 @@ const SORT_OPTIONS = [ { value: "bestmatch", label: "Best Match" }, ]; +const EXPORT_OPTIONS = [ + { + key: "csv", + label: "Export CSV", + }, + { + key: "xml", + label: "Export XML", + }, +]; + const getValueFromLocation = (value = "mostrecent") => { const choices = { mostrecent: "Newest First", @@ -30,6 +42,45 @@ const Header = ({ let searchParams = queryString.parse(location.search); let sortParam = searchParams.sort || "mostrecent"; + + const onExport = async (mimetype) => { + let acceptHeader = null; + if (mimetype == "csv") { acceptHeader = "application/csv"} + else if (mimetype == "xml") { acceptHeader = "application/marcxml+xml"} + else return; + + const timestamp = new Date().getTime(); + const filename = `export-${timestamp}.${mimetype}` + + let record_type = null; + if (location.pathname == DRAFTS) { record_type = "deposits"} + else if (location.pathname == PUBLISHED) { record_type = "records"} + else return; + + try { + const apiUrl = `/api/${record_type}/${location.search}`; + const headers = { 'Accept': acceptHeader }; + + const response = await fetch(apiUrl, { headers }); + + if (!response.ok) { + throw new Error(`Error: ${response.statusText}`); + } + + const blob = await response.blob(); + const downloadUrl = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = downloadUrl; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + link.parentNode.removeChild(link); + window.URL.revokeObjectURL(downloadUrl); + } catch (error) { + console.error('Download failed', error); + } + }; + // let isDescending = sortParam && sortParam[0] == "-"; // TODO: For asc/desc sorting // let sortValue = isDescending ? sortParam.substring(1) : sortParam; @@ -60,7 +111,7 @@ const Header = ({ )} {shouldDisplayFacetButton && ( - )} @@ -82,6 +133,16 @@ const Header = ({ ))} + onExport(e.key) + }} + > +