diff --git a/package-lock.json b/package-lock.json index 3931a1c..ccb8f1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,10 @@ "dependencies": { "bootstrap": "^5.3.2", "bootstrap-icons": "^1.10.3", + "file-saver": "^2.0.5", "mc-react-header": "^0.3.1", "mc-react-library": "^0.3.1", - "mc-react-ptable-materials-grid": "^0.7.3", + "mc-react-ptable-materials-grid": "^0.8.0", "mc-react-structure-visualizer": "^0.7.2", "plotly.js": "^2.6.2", "react": "^18.1.0", @@ -5705,17 +5706,25 @@ "node": ">=8.9" } }, + "node_modules/ag-charts-types": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.1.0.tgz", + "integrity": "sha512-pk9ft8hbgTXJ/thI/SEUR1BoauNplYExpcHh7tMOqVikoDsta1O15TB1ZL4XWnl4TPIzROBmONKsz7d8a2HBuQ==" + }, "node_modules/ag-grid-community": { - "version": "31.3.4", - "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-31.3.4.tgz", - "integrity": "sha512-jOxQO86C6eLnk1GdP24HB6aqaouFzMWizgfUwNY5MnetiWzz9ZaAmOGSnW/XBvdjXvC5Fpk3gSbvVKKQ7h9kBw==" + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-32.1.0.tgz", + "integrity": "sha512-RVvkjRH61nuCXwIqTKQPqNbKR+8cGBKw7S1qmmMXsy0pCBAJaQn4kL3v31hKHxDtV4bPscBXLFKGnKzHuss0GQ==", + "dependencies": { + "ag-charts-types": "10.1.0" + } }, "node_modules/ag-grid-react": { - "version": "31.3.4", - "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-31.3.4.tgz", - "integrity": "sha512-WmPASHRFGSTxCMRStWG5bRtln0Ugsdqbb3+Y8sEyGHeLw4hXqfpqie3lT9kqCOl7wPWUjCpwmFdXzRnWPmyyeg==", + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-32.1.0.tgz", + "integrity": "sha512-GDbtvU3aicSajWXWxvQio5ZaPqJDx2jzgRBKQf1RF1IVzL+XATDmLFNuMND0+wJ/VW/xUjBFjiq9W1fjXg/DCA==", "dependencies": { - "ag-grid-community": "31.3.4", + "ag-grid-community": "32.1.0", "prop-types": "^15.8.1" }, "peerDependencies": { @@ -9790,6 +9799,11 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -14185,16 +14199,18 @@ } }, "node_modules/mc-react-ptable-materials-grid": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/mc-react-ptable-materials-grid/-/mc-react-ptable-materials-grid-0.7.3.tgz", - "integrity": "sha512-P5SimnNeH9JFQnh/btZJg8xRkDGb55zdphlcEpxto60lDIiNnb0gN++4zxy7ipNt0re56eJToSkhGs0kAJjzzA==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mc-react-ptable-materials-grid/-/mc-react-ptable-materials-grid-0.8.0.tgz", + "integrity": "sha512-wll8BIpYLbdbec1XTsIZfj0WENAEmCC6KBVCs9QqPMoxPdXpEtoDyQDs8S4gYAP2yT1JTWsnd9uSVQKVEwzGEQ==", "dependencies": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", - "ag-grid-community": "^31.3.4", - "ag-grid-react": "^31.3.4", + "ag-grid-community": "^32.1.0", + "ag-grid-react": "^32.1.0", "bootstrap": "^5.2.2", + "file-saver": "^2.0.5", + "mc-react-library": "^0.3.1", "react": "^18.1.0", "react-bootstrap": "^2.6.0", "react-dom": "^18.1.0", @@ -24736,17 +24752,25 @@ "regex-parser": "^2.2.11" } }, + "ag-charts-types": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.1.0.tgz", + "integrity": "sha512-pk9ft8hbgTXJ/thI/SEUR1BoauNplYExpcHh7tMOqVikoDsta1O15TB1ZL4XWnl4TPIzROBmONKsz7d8a2HBuQ==" + }, "ag-grid-community": { - "version": "31.3.4", - "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-31.3.4.tgz", - "integrity": "sha512-jOxQO86C6eLnk1GdP24HB6aqaouFzMWizgfUwNY5MnetiWzz9ZaAmOGSnW/XBvdjXvC5Fpk3gSbvVKKQ7h9kBw==" + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-32.1.0.tgz", + "integrity": "sha512-RVvkjRH61nuCXwIqTKQPqNbKR+8cGBKw7S1qmmMXsy0pCBAJaQn4kL3v31hKHxDtV4bPscBXLFKGnKzHuss0GQ==", + "requires": { + "ag-charts-types": "10.1.0" + } }, "ag-grid-react": { - "version": "31.3.4", - "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-31.3.4.tgz", - "integrity": "sha512-WmPASHRFGSTxCMRStWG5bRtln0Ugsdqbb3+Y8sEyGHeLw4hXqfpqie3lT9kqCOl7wPWUjCpwmFdXzRnWPmyyeg==", + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-32.1.0.tgz", + "integrity": "sha512-GDbtvU3aicSajWXWxvQio5ZaPqJDx2jzgRBKQf1RF1IVzL+XATDmLFNuMND0+wJ/VW/xUjBFjiq9W1fjXg/DCA==", "requires": { - "ag-grid-community": "31.3.4", + "ag-grid-community": "32.1.0", "prop-types": "^15.8.1" } }, @@ -27804,6 +27828,11 @@ "schema-utils": "^3.0.0" } }, + "file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -31178,16 +31207,18 @@ "requires": {} }, "mc-react-ptable-materials-grid": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/mc-react-ptable-materials-grid/-/mc-react-ptable-materials-grid-0.7.3.tgz", - "integrity": "sha512-P5SimnNeH9JFQnh/btZJg8xRkDGb55zdphlcEpxto60lDIiNnb0gN++4zxy7ipNt0re56eJToSkhGs0kAJjzzA==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mc-react-ptable-materials-grid/-/mc-react-ptable-materials-grid-0.8.0.tgz", + "integrity": "sha512-wll8BIpYLbdbec1XTsIZfj0WENAEmCC6KBVCs9QqPMoxPdXpEtoDyQDs8S4gYAP2yT1JTWsnd9uSVQKVEwzGEQ==", "requires": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", - "ag-grid-community": "^31.3.4", - "ag-grid-react": "^31.3.4", + "ag-grid-community": "^32.1.0", + "ag-grid-react": "^32.1.0", "bootstrap": "^5.2.2", + "file-saver": "^2.0.5", + "mc-react-library": "^0.3.1", "react": "^18.1.0", "react-bootstrap": "^2.6.0", "react-dom": "^18.1.0", diff --git a/package.json b/package.json index 01ae44b..2aa2539 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,10 @@ "dependencies": { "bootstrap": "^5.3.2", "bootstrap-icons": "^1.10.3", + "file-saver": "^2.0.5", "mc-react-header": "^0.3.1", "mc-react-library": "^0.3.1", - "mc-react-ptable-materials-grid": "^0.7.3", + "mc-react-ptable-materials-grid": "^0.8.0", "mc-react-structure-visualizer": "^0.7.2", "plotly.js": "^2.6.2", "react": "^18.1.0", diff --git a/src/MainPage/DownloadButton.css b/src/MainPage/DownloadButton.css new file mode 100644 index 0000000..7086104 --- /dev/null +++ b/src/MainPage/DownloadButton.css @@ -0,0 +1,22 @@ +.aggrid-style-button { + padding: 10px; + background-color: #f8f8f8; + color: #000000; + font-family: var(--ag-font-family); + font-size: 12px; + font-weight: bold; + border: 1px solid #babfc7; + cursor: pointer; + margin-bottom: 3px; + margin-top: 2px; +} + +.aggrid-style-button:hover { + background-color: #dbdbdb; +} + +.aggrid-style-button-disabled { + opacity: 0.4; + cursor: none; + pointer-events: none; +} diff --git a/src/MainPage/DownloadButton.jsx b/src/MainPage/DownloadButton.jsx new file mode 100644 index 0000000..cfe44de --- /dev/null +++ b/src/MainPage/DownloadButton.jsx @@ -0,0 +1,36 @@ +import { saveAs } from "file-saver"; + +import "./DownloadButton.css"; + +export const DownloadButton = ({ materialSelectorRef, disabled }) => { + /* + Note: the plan is to potentially also include direct download links (via the AiiDA rest api) + to each of the materials in the downloaded file, but currently the index page doesn't have + the structure UUIDs. Including them in the default index download is not great, as they would + increase the initial download size considerably, while not really needed for the table. + + Therefore, it probably might make sense to implement an additional endpoint, e.g. pbe-v1/uuids + that is only called when this download button is clicked. + */ + + const handleDownload = () => { + if (materialSelectorRef.current) { + const data = materialSelectorRef.current.getFilteredRows(); + const json = JSON.stringify(data, null, 2); + const blob = new Blob([json], { type: "application/json" }); + const filename = `mc3d_index_data_n${data.length}.json`; + saveAs(blob, filename); + } + }; + + return ( + + ); +}; diff --git a/src/MainPage/index.jsx b/src/MainPage/index.jsx index 9c1f1cf..c63827a 100644 --- a/src/MainPage/index.jsx +++ b/src/MainPage/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } from "react"; import "./index.css"; @@ -16,12 +16,13 @@ import { restapiText } from "./restapi"; import { loadDataMc3d } from "./loadDataMc3d"; +import { DownloadButton } from "./DownloadButton"; + import Form from "react-bootstrap/Form"; function MainPage() { const [columns, setColumns] = useState([]); const [rows, setRows] = useState([]); - const [method, setMethod] = useState("pbe-v1"); useEffect(() => { @@ -37,6 +38,8 @@ function MainPage() { setMethod(event.target.value); }; + const materialSelectorRef = useRef(null); + return ( - + + {aboutText} diff --git a/src/MainPage/loadDataMc3d.js b/src/MainPage/loadDataMc3d.js index aeb62d2..ba22a14 100644 --- a/src/MainPage/loadDataMc3d.js +++ b/src/MainPage/loadDataMc3d.js @@ -151,7 +151,9 @@ function formatRows(indexData, metadata, method) { let row = {}; Object.entries(entry).map(([key, value]) => { - row[labelMap[key]] = value; + if (key in labelMap) { + row[labelMap[key]] = value; + } }); let modifiedKeys = {