diff --git a/config.xml b/config.xml index 18100a284..499ee606f 100644 --- a/config.xml +++ b/config.xml @@ -1,5 +1,8 @@ - + Network Canvas Interviewer A tool for conducting Network Canvas Interviews. @@ -16,6 +19,7 @@ + @@ -81,4 +85,4 @@ - \ No newline at end of file + diff --git a/package-lock.json b/package-lock.json index cbc91f9ba..72bd56ae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "network-canvas-interviewer", - "version": "6.5.1", + "version": "6.5.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "network-canvas-interviewer", - "version": "6.5.1", + "version": "6.5.2", "dependencies": { "@babel/runtime": "7.10.1", + "@xmldom/xmldom": "~0.8.10", "archiver": "^4.0.1", "d3-force": "~3.0.0", "dmg-builder": "~23.6.0", @@ -51,8 +52,8 @@ "connected-react-router": "^6.8.0", "cordova-android": "~12.0.0", "cordova-ios": "~7.0.0", - "cordova-plugin-file": "github:apache/cordova-plugin-file", - "cordova-plugin-file-transfer": "github:apache/cordova-plugin-file-transfer", + "cordova-plugin-file": "github:apache/cordova-plugin-file#265a932", + "cordova-plugin-file-transfer": "github:apache/cordova-plugin-file-transfer#f12b73e", "cordova-plugin-fullscreen": "github:mesmotronic/cordova-plugin-fullscreen", "cordova-plugin-ionic-keyboard": "github:ionic-team/cordova-plugin-ionic-keyboard", "cordova-plugin-network-canvas-client": "github:complexdatacollective/cordova-plugin-network-canvas-client", @@ -149,7 +150,6 @@ "whatwg-fetch": "2.0.3", "worker-loader": "^2.0.0", "xml2js": "~0.4.23", - "xmldom": "~0.1.27", "xss": "^0.3.4" }, "engines": { @@ -157,11 +157,6 @@ "npm": "8.19.4" } }, - "../cordova-plugin-network-canvas-client": { - "version": "0.0.2", - "extraneous": true, - "license": "GPL-3.0-or-later" - }, "node_modules/@ampproject/remapping": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", @@ -6034,6 +6029,14 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -9928,8 +9931,8 @@ } }, "node_modules/cordova-plugin-file": { - "version": "8.0.1-dev", - "resolved": "git+ssh://git@github.com/apache/cordova-plugin-file.git#faba1bf0f1479cafe5ed256bc0181fe10768527f", + "version": "8.0.2-dev", + "resolved": "git+ssh://git@github.com/apache/cordova-plugin-file.git#265a932f3b5d11739fd08c0437477f441f6212c7", "dev": true, "license": "Apache-2.0", "engines": { @@ -9950,8 +9953,8 @@ } }, "node_modules/cordova-plugin-file-transfer": { - "version": "2.0.0-dev", - "resolved": "git+ssh://git@github.com/apache/cordova-plugin-file-transfer.git#06335fea28f7ad4d815aa621e02823a63b0a9bc6", + "version": "2.0.1-dev", + "resolved": "git+ssh://git@github.com/apache/cordova-plugin-file-transfer.git#f12b73eb0ba70536072eeab89843c96082fce512", "dev": true, "license": "Apache-2.0", "engines": { @@ -9985,7 +9988,7 @@ }, "node_modules/cordova-plugin-network-canvas-client": { "version": "0.0.2", - "resolved": "git+ssh://git@github.com/complexdatacollective/cordova-plugin-network-canvas-client.git#4bf75df4d6bf975a26d85ce2db02c23541b7e6aa", + "resolved": "git+ssh://git@github.com/complexdatacollective/cordova-plugin-network-canvas-client.git#364662b79e1a97ac88ec0b0e520e497e810b1f0f", "dev": true, "license": "GPL-3.0-or-later" }, @@ -36298,16 +36301,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "node_modules/xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha512-7WpJBYwyhvsddFJA51SOIU0Be9W44sbGGjc6Z3ly8Wx/Wl7nriMPZ5xf6Np9ASlJ6gACfXcTLukm4DtX372lFw==", - "deprecated": "Deprecated due to CVE-2021-21366 resolved in 0.5.0", - "dev": true, - "engines": { - "node": ">=0.1" - } - }, "node_modules/xss": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/xss/-/xss-0.3.8.tgz", @@ -40709,6 +40702,11 @@ "@xtuc/long": "4.2.2" } }, + "@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==" + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -43780,14 +43778,14 @@ } }, "cordova-plugin-file": { - "version": "git+ssh://git@github.com/apache/cordova-plugin-file.git#faba1bf0f1479cafe5ed256bc0181fe10768527f", + "version": "git+ssh://git@github.com/apache/cordova-plugin-file.git#265a932f3b5d11739fd08c0437477f441f6212c7", "dev": true, - "from": "cordova-plugin-file@github:apache/cordova-plugin-file" + "from": "cordova-plugin-file@github:apache/cordova-plugin-file#265a932" }, "cordova-plugin-file-transfer": { - "version": "git+ssh://git@github.com/apache/cordova-plugin-file-transfer.git#06335fea28f7ad4d815aa621e02823a63b0a9bc6", + "version": "git+ssh://git@github.com/apache/cordova-plugin-file-transfer.git#f12b73eb0ba70536072eeab89843c96082fce512", "dev": true, - "from": "cordova-plugin-file-transfer@github:apache/cordova-plugin-file-transfer" + "from": "cordova-plugin-file-transfer@github:apache/cordova-plugin-file-transfer#f12b73e" }, "cordova-plugin-fullscreen": { "version": "git+ssh://git@github.com/mesmotronic/cordova-plugin-fullscreen.git#942a9592e5ffd23b588661bfbaed708d0b56f1ca", @@ -43800,7 +43798,7 @@ "from": "cordova-plugin-ionic-keyboard@github:ionic-team/cordova-plugin-ionic-keyboard" }, "cordova-plugin-network-canvas-client": { - "version": "git+ssh://git@github.com/complexdatacollective/cordova-plugin-network-canvas-client.git#4bf75df4d6bf975a26d85ce2db02c23541b7e6aa", + "version": "git+ssh://git@github.com/complexdatacollective/cordova-plugin-network-canvas-client.git#364662b79e1a97ac88ec0b0e520e497e810b1f0f", "dev": true, "from": "cordova-plugin-network-canvas-client@github:complexdatacollective/cordova-plugin-network-canvas-client" }, @@ -64423,12 +64421,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha512-7WpJBYwyhvsddFJA51SOIU0Be9W44sbGGjc6Z3ly8Wx/Wl7nriMPZ5xf6Np9ASlJ6gACfXcTLukm4DtX372lFw==", - "dev": true - }, "xss": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/xss/-/xss-0.3.8.tgz", diff --git a/package.json b/package.json index c098239ba..0e7613adf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "network-canvas-interviewer", - "version": "6.5.1", + "version": "6.5.2", "productName": "Network Canvas Interviewer", "description": "A tool for conducting Network Canvas Interviews.", "author": "Complex Data Collective", @@ -78,8 +78,8 @@ "connected-react-router": "^6.8.0", "cordova-android": "~12.0.0", "cordova-ios": "~7.0.0", - "cordova-plugin-file": "github:apache/cordova-plugin-file", - "cordova-plugin-file-transfer": "github:apache/cordova-plugin-file-transfer", + "cordova-plugin-file": "github:apache/cordova-plugin-file#265a932", + "cordova-plugin-file-transfer": "github:apache/cordova-plugin-file-transfer#f12b73e", "cordova-plugin-fullscreen": "github:mesmotronic/cordova-plugin-fullscreen", "cordova-plugin-ionic-keyboard": "github:ionic-team/cordova-plugin-ionic-keyboard", "cordova-plugin-network-canvas-client": "github:complexdatacollective/cordova-plugin-network-canvas-client", @@ -176,11 +176,11 @@ "whatwg-fetch": "2.0.3", "worker-loader": "^2.0.0", "xml2js": "~0.4.23", - "xmldom": "~0.1.27", "xss": "^0.3.4" }, "dependencies": { "@babel/runtime": "7.10.1", + "@xmldom/xmldom": "~0.8.10", "archiver": "^4.0.1", "d3-force": "~3.0.0", "dmg-builder": "~23.6.0", diff --git a/public/package.json b/public/package.json index 7ab23555b..bef634fc5 100644 --- a/public/package.json +++ b/public/package.json @@ -1,6 +1,6 @@ { "name": "network-canvas-interviewer", - "version": "6.5.1", + "version": "6.5.2", "productName": "Network Canvas Interviewer", "description": "A tool for conducting Network Canvas Interviews.", "author": "Complex Data Collective", diff --git a/src/containers/SessionManagementScreen/SessionManagementScreen.js b/src/containers/SessionManagementScreen/SessionManagementScreen.js index b453fc482..65f080fb9 100644 --- a/src/containers/SessionManagementScreen/SessionManagementScreen.js +++ b/src/containers/SessionManagementScreen/SessionManagementScreen.js @@ -23,12 +23,14 @@ const fatalExportErrorAction = withErrorDialog((error) => ({ error, })); +const getInitialFilename = () => `networkCanvasExport-${Date.now()}`; + const DataExportScreen = ({ show, onClose }) => { const [step, setStep] = useState(3); const [selectedSessions, setSelectedSessions] = useState([]); // Set the default filename to 'networkCanvasExport-' - const [filename, setFilename] = useState(`networkCanvasExport-${Date.now()}`); + const [filename, setFilename] = useState(getInitialFilename()); const [abortHandlers, setAbortHandlers] = useState(null); const pairedServer = useSelector((state) => state.pairedServer); @@ -40,6 +42,7 @@ const DataExportScreen = ({ show, onClose }) => { const openDialog = (dialog) => dispatch(dialogActions.openDialog(dialog)); const reset = () => { + setFilename(getInitialFilename()); setSelectedSessions([]); setStep(1); }; diff --git a/src/utils/network-exporters b/src/utils/network-exporters index 8c0e9f39e..376417cf4 160000 --- a/src/utils/network-exporters +++ b/src/utils/network-exporters @@ -1 +1 @@ -Subproject commit 8c0e9f39ec49d85f9b7d83e270b2a46105cc782b +Subproject commit 376417cf4aba486431d65453d415489b5f414dfe diff --git a/src/utils/protocol/downloadProtocol.js b/src/utils/protocol/downloadProtocol.js index c38c72617..b0ecc04b5 100644 --- a/src/utils/protocol/downloadProtocol.js +++ b/src/utils/protocol/downloadProtocol.js @@ -2,7 +2,7 @@ /* global FileTransfer */ import uuid from 'uuid/v4'; import environments from '../environments'; -import inEnvironment from '../Environment'; +import inEnvironment, { isIOS } from '../Environment'; import { writeFile, tempDataPath } from '../filesystem'; import friendlyErrorMessage from '../../utils/friendlyErrorMessage'; import ApiClient from '../../utils/ApiClient'; @@ -36,8 +36,8 @@ const downloadProtocol = inEnvironment((environment) => { if (environment === environments.ELECTRON) { const request = require('request-promise-native'); const destination = path.join(tempDataPath(), getProtocolName()); - return (uri, pairedServer = false) => { + let promisedResponse; if (pairedServer) { promisedResponse = new ApiClient(pairedServer).downloadProtocol(uri); @@ -56,29 +56,41 @@ const downloadProtocol = inEnvironment((environment) => { } if (environment === environments.CORDOVA) { - const destination = `${tempDataPath()}${getProtocolName()}` return (uri, pairedServer) => { let promisedResponse; + if (pairedServer) { + // on iOS, the cordova-plugin-network-canvas-client wants the destination + // to be a folder, not a file. It assigns a temp filename itself. + // + // however, on android it needs to be a file. + const destination = isIOS() ? tempDataPath() : `${tempDataPath()}${getProtocolName()}`; + promisedResponse = new ApiClient(pairedServer) // .addTrustedCert() is not required, assuming we've just fetched the protocol list .downloadProtocol(uri, destination) - .then(() => destination); + .then((result) => { + // Result is a FileEntry object + return result.nativeURL; + }) } else { promisedResponse = getURL(uri) .then(url => url.href) .catch(urlError) .then(href => new Promise((resolve, reject) => { + // The filetransfer plugin requires a folder to write to + const destinationWithFolder = `${tempDataPath()}${getProtocolName()}`; + const fileTransfer = new FileTransfer(); - console.log('fileTransfer', destination); fileTransfer.download( href, - destination, - () => resolve(destination), + destinationWithFolder, + () => resolve(destinationWithFolder), error => reject(error), ); })); } + return promisedResponse .catch((error) => { const getErrorMessage = ({ code }) => {