From 799f67ea49c20455643a6c0f9716569370023ab4 Mon Sep 17 00:00:00 2001
From: msramalho <19508417+msramalho@users.noreply.github.com>
Date: Wed, 6 Apr 2022 18:57:09 +0200
Subject: [PATCH] implements csv+json downloads
---
config.js | 1 +
package-lock.json | 85 ++++++++++++++++++-----
package.json | 1 +
src/common/constants.js | 1 +
src/common/data/copy.json | 19 ++++-
src/common/utilities.js | 13 ++++
src/components/Layout.js | 3 +-
src/components/Toolbar.js | 51 ++++++++++----
src/components/controls/DownloadButton.js | 84 ++++++++++++++++++++++
src/components/controls/DownloadPanel.js | 21 ++++++
src/scss/toolbar.scss | 15 +++-
src/store/initial.js | 6 ++
12 files changed, 265 insertions(+), 35 deletions(-)
create mode 100644 src/components/controls/DownloadButton.js
create mode 100644 src/components/controls/DownloadPanel.js
diff --git a/config.js b/config.js
index c610c88..0ea2f6d 100644
--- a/config.js
+++ b/config.js
@@ -147,6 +147,7 @@ module.exports = {
COLOR_BY_ASSOCIATION: true,
USE_ASSOCIATIONS: true,
USE_FULLSCREEN: true,
+ USE_DOWNLOAD: true,
USE_SOURCES: true,
USE_SPOTLIGHTS: false,
USE_SHAPES: false,
diff --git a/package-lock.json b/package-lock.json
index ed221a1..ddc7d5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -47,6 +47,7 @@
"jest-resolve": "26.6.0",
"jest-watch-typeahead": "0.6.1",
"joi": "^14.0.1",
+ "json2csv": "^5.0.7",
"leaflet": "^1.0.3",
"lint-staged": "^10.5.3",
"marked": "^0.7.0",
@@ -15261,6 +15262,31 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"devOptional": true
},
+ "node_modules/json2csv": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.7.tgz",
+ "integrity": "sha512-YRZbUnyaJZLZUJSRi2G/MqahCyRv9n/ds+4oIetjDF3jWQA7AG7iSeKTiZiCNqtMZM7HDyt0e/W6lEnoGEmMGA==",
+ "dependencies": {
+ "commander": "^6.1.0",
+ "jsonparse": "^1.3.1",
+ "lodash.get": "^4.4.2"
+ },
+ "bin": {
+ "json2csv": "bin/json2csv.js"
+ },
+ "engines": {
+ "node": ">= 10",
+ "npm": ">= 6.13.0"
+ }
+ },
+ "node_modules/json2csv/node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@@ -15288,6 +15314,14 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "engines": [
+ "node >= 0.2.0"
+ ]
+ },
"node_modules/jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -15845,6 +15879,11 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -24434,19 +24473,6 @@
"is-typedarray": "^1.0.0"
}
},
- "node_modules/typescript": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
- "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=4.2.0"
- }
- },
"node_modules/ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
@@ -37962,6 +37988,23 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"devOptional": true
},
+ "json2csv": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.7.tgz",
+ "integrity": "sha512-YRZbUnyaJZLZUJSRi2G/MqahCyRv9n/ds+4oIetjDF3jWQA7AG7iSeKTiZiCNqtMZM7HDyt0e/W6lEnoGEmMGA==",
+ "requires": {
+ "commander": "^6.1.0",
+ "jsonparse": "^1.3.1",
+ "lodash.get": "^4.4.2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
+ }
+ }
+ },
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@@ -37981,6 +38024,11 @@
"universalify": "^2.0.0"
}
},
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+ },
"jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -38407,6 +38455,11 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+ },
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -45128,12 +45181,6 @@
"is-typedarray": "^1.0.0"
}
},
- "typescript": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
- "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
- "peer": true
- },
"ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
diff --git a/package.json b/package.json
index cf51440..b1592be 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"jest-resolve": "26.6.0",
"jest-watch-typeahead": "0.6.1",
"joi": "^14.0.1",
+ "json2csv": "^5.0.7",
"leaflet": "^1.0.3",
"lint-staged": "^10.5.3",
"marked": "^0.7.0",
diff --git a/src/common/constants.js b/src/common/constants.js
index 0ad7ec5..d70ef22 100644
--- a/src/common/constants.js
+++ b/src/common/constants.js
@@ -11,6 +11,7 @@ export const DEFAULT_TAB_ICONS = {
NARRATIVE: "timeline",
FILTER: "filter_list",
SHAPE: "change_history",
+ DOWNLOAD: "download"
};
export const AVAILABLE_SHAPES = {
diff --git a/src/common/data/copy.json b/src/common/data/copy.json
index 6847064..781d3e1 100644
--- a/src/common/data/copy.json
+++ b/src/common/data/copy.json
@@ -159,7 +159,24 @@
"explore_by_shapes__title": "Explore events by shape breakdown",
"explore_by_shape__description": "Shapes map to a given type of event that appears on the timeline.
Select the shape marker to toggle this type of event on / off",
"fullscreen_enter": "Fullscreen",
- "fullscreen_exit": "Exit Fullscreen"
+ "fullscreen_exit": "Exit Fullscreen",
+ "download": {
+ "button": "Download",
+ "panel":{
+ "title": "Download events",
+ "description": "Export the most recent available events in different formats.",
+ "formats": {
+ "csv": {
+ "label": "CSV",
+ "description": "CSV file where sources and filters are concatenated into a single column due to data structure limitations."
+ },
+ "json": {
+ "label": "JSON",
+ "description": "JSON file where each event is a structured object containing nested arrays of sources and filters."
+ }
+ }
+ }
+ }
},
"timeline": {
"labels_title": "Testimonies",
diff --git a/src/common/utilities.js b/src/common/utilities.js
index bdcb50a..0a1e775 100644
--- a/src/common/utilities.js
+++ b/src/common/utilities.js
@@ -576,4 +576,17 @@ export function getFilterIdx(
else return 0;
}
+export function downloadAsFile(filename, content) {
+ let element = document.createElement('a');
+ element.setAttribute('href', `data:application/octet-stream;charset=utf-8,${encodeURIComponent(content)}`);
+ element.setAttribute('download', filename);
+
+ element.style.display = 'none';
+ document.body.appendChild(element);
+
+ element.click();
+
+ document.body.removeChild(element);
+}
+
export const isEmptyString = (s) => s.length === 0;
diff --git a/src/components/Layout.js b/src/components/Layout.js
index 0f3e358..376d585 100644
--- a/src/components/Layout.js
+++ b/src/components/Layout.js
@@ -301,12 +301,13 @@ class Dashboard extends React.Component {
overflowY: "scroll",
textAlign: "justify",
};
-
+
return (
{description}
+