@openneuro/app 4.17.1 → 4.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/scripts/dataset/download/download-script.tsx +94 -0
- package/src/scripts/dataset/files/file-tree.tsx +1 -0
- package/src/scripts/dataset/files/file.tsx +6 -1
- package/src/scripts/dataset/routes/download-dataset.tsx +2 -0
- package/src/scripts/uploader/upload-issues.jsx +8 -1
- package/src/scripts/uploader/upload-select.jsx +13 -0
- package/src/scripts/uploader/uploader.jsx +11 -0
- package/src/scripts/utils/schema-validator.js +196477 -0
- package/src/scripts/validation/validation-results.issues.issue.jsx +1 -1
- package/src/scripts/validation/validation-results.issues.jsx +27 -11
- package/src/scripts/validation/validation-results.jsx +1 -1
- package/src/scripts/workers/schema.ts +13 -0
- package/src/scripts/workers/schema.worker.ts +29 -0
- package/src/scripts/workers/worker-interface.ts +4 -1
- package/vite.config.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/app",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.18.0",
|
|
4
4
|
"description": "React JS web frontend for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "public/client.js",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"@elastic/apm-rum": "5.11.0",
|
|
20
20
|
"@emotion/react": "11.6.0",
|
|
21
21
|
"@emotion/styled": "11.6.0",
|
|
22
|
-
"@niivue/niivue": "0.
|
|
23
|
-
"@openneuro/client": "^4.
|
|
24
|
-
"@openneuro/components": "^4.
|
|
22
|
+
"@niivue/niivue": "0.33.1",
|
|
23
|
+
"@openneuro/client": "^4.18.0",
|
|
24
|
+
"@openneuro/components": "^4.18.0",
|
|
25
25
|
"bids-validator": "1.10.0",
|
|
26
26
|
"bytes": "^3.0.0",
|
|
27
27
|
"comlink": "^4.0.5",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"publishConfig": {
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "0135730a3d7ff196b43abb69a6c89e6699c6a19e"
|
|
85
85
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a download script for this dataset
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { useLazyQuery, gql } from '@apollo/client'
|
|
6
|
+
|
|
7
|
+
function inlineDownload(filename, data): void {
|
|
8
|
+
const element = document.createElement('a')
|
|
9
|
+
element.setAttribute(
|
|
10
|
+
'href',
|
|
11
|
+
'data:text/x-shellscript;charset=utf-8,' + encodeURIComponent(data),
|
|
12
|
+
)
|
|
13
|
+
element.setAttribute('download', filename)
|
|
14
|
+
|
|
15
|
+
element.style.display = 'none'
|
|
16
|
+
document.body.appendChild(element)
|
|
17
|
+
|
|
18
|
+
element.click()
|
|
19
|
+
|
|
20
|
+
document.body.removeChild(element)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function generateDownloadScript(data): string {
|
|
24
|
+
let script = '#!/bin/sh\n'
|
|
25
|
+
for (const f of data.snapshot.downloadFiles) {
|
|
26
|
+
script += `curl --create-dirs ${f.urls[0]} -o ${f.filename}\n`
|
|
27
|
+
}
|
|
28
|
+
return script
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface DownloadS3DerivativesProps {
|
|
32
|
+
datasetId: string
|
|
33
|
+
snapshotTag: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const getSnapshotDownload = gql`
|
|
37
|
+
query snapshot($datasetId: ID!, $tag: String!) {
|
|
38
|
+
snapshot(datasetId: $datasetId, tag: $tag) {
|
|
39
|
+
id
|
|
40
|
+
downloadFiles {
|
|
41
|
+
id
|
|
42
|
+
directory
|
|
43
|
+
filename
|
|
44
|
+
urls
|
|
45
|
+
size
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
export const DownloadScript = ({
|
|
52
|
+
datasetId,
|
|
53
|
+
snapshotTag,
|
|
54
|
+
}: DownloadS3DerivativesProps): JSX.Element => {
|
|
55
|
+
const [getDownload, { loading, data }] = useLazyQuery(getSnapshotDownload, {
|
|
56
|
+
variables: {
|
|
57
|
+
datasetId: datasetId,
|
|
58
|
+
tag: snapshotTag,
|
|
59
|
+
},
|
|
60
|
+
errorPolicy: 'all',
|
|
61
|
+
})
|
|
62
|
+
if (data) {
|
|
63
|
+
const script = generateDownloadScript(data)
|
|
64
|
+
inlineDownload(`${datasetId}-${snapshotTag}.sh`, script)
|
|
65
|
+
}
|
|
66
|
+
// This feature is only implemented for snapshots
|
|
67
|
+
if (snapshotTag) {
|
|
68
|
+
return (
|
|
69
|
+
<div>
|
|
70
|
+
<h4>Download with a shell script</h4>
|
|
71
|
+
<p>
|
|
72
|
+
A script is available to download with only curl. This may be useful
|
|
73
|
+
if your download environment makes it difficult to install DataLad or
|
|
74
|
+
Node.js.
|
|
75
|
+
</p>
|
|
76
|
+
<p>
|
|
77
|
+
{loading ? (
|
|
78
|
+
'Loading...'
|
|
79
|
+
) : (
|
|
80
|
+
<a
|
|
81
|
+
href="#"
|
|
82
|
+
onClick={(): void => {
|
|
83
|
+
void getDownload()
|
|
84
|
+
}}>
|
|
85
|
+
Download shell script
|
|
86
|
+
</a>
|
|
87
|
+
)}
|
|
88
|
+
</p>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default DownloadScript
|
|
@@ -91,6 +91,7 @@ interface FileProps {
|
|
|
91
91
|
annexed: boolean
|
|
92
92
|
annexKey: string
|
|
93
93
|
datasetPermissions: string[]
|
|
94
|
+
urls: string[]
|
|
94
95
|
toggleFileToDelete: ({
|
|
95
96
|
id,
|
|
96
97
|
path,
|
|
@@ -117,6 +118,7 @@ const File = ({
|
|
|
117
118
|
datasetPermissions,
|
|
118
119
|
toggleFileToDelete,
|
|
119
120
|
isFileToBeDeleted,
|
|
121
|
+
urls,
|
|
120
122
|
}: FileProps): JSX.Element => {
|
|
121
123
|
const { icon, color } = getFileIcon(filename)
|
|
122
124
|
const snapshotVersionPath = snapshotTag ? `/versions/${snapshotTag}` : ''
|
|
@@ -137,7 +139,10 @@ const File = ({
|
|
|
137
139
|
<Tooltip tooltip={`Download: ${bytes.format(size) as string}`}>
|
|
138
140
|
<span className="edit-file download-file">
|
|
139
141
|
<a
|
|
140
|
-
href={
|
|
142
|
+
href={
|
|
143
|
+
urls?.[0] ||
|
|
144
|
+
apiPath(datasetId, snapshotTag, filePath(path, filename))
|
|
145
|
+
}
|
|
141
146
|
download
|
|
142
147
|
aria-label="download file">
|
|
143
148
|
<i className="fa fa-download" />
|
|
@@ -8,6 +8,7 @@ import DownloadCommandLine from '../download/download-command-line.jsx'
|
|
|
8
8
|
import DownloadDatalad from '../download/download-datalad.jsx'
|
|
9
9
|
import { DatasetPageBorder } from './styles/dataset-page-border'
|
|
10
10
|
import { HeaderRow3 } from './styles/header-row'
|
|
11
|
+
import { DownloadScript } from '../download/download-script'
|
|
11
12
|
|
|
12
13
|
const DownloadDataset = ({ worker, datasetPermissions }) => {
|
|
13
14
|
const { datasetId, tag: snapshotTag } = useParams()
|
|
@@ -34,6 +35,7 @@ const DownloadDataset = ({ worker, datasetPermissions }) => {
|
|
|
34
35
|
workerId={workerId}
|
|
35
36
|
datasetPermissions={datasetPermissions}
|
|
36
37
|
/>
|
|
38
|
+
<DownloadScript datasetId={datasetId} snapshotTag={snapshotTag} />
|
|
37
39
|
</DatasetPageBorder>
|
|
38
40
|
)
|
|
39
41
|
}
|
|
@@ -5,6 +5,7 @@ import { Loading } from '@openneuro/components/loading'
|
|
|
5
5
|
import Results from '../validation/validation-results.jsx'
|
|
6
6
|
import UploaderContext from './uploader-context.js'
|
|
7
7
|
import validate from '../workers/validate'
|
|
8
|
+
import schemaValidate from '../workers/schema'
|
|
8
9
|
|
|
9
10
|
const UploadValidatorStatus = ({ issues, next, reset }) => {
|
|
10
11
|
const errorCount = issues.errors.length
|
|
@@ -70,7 +71,11 @@ class UploadValidator extends React.Component {
|
|
|
70
71
|
blacklistModalities: ['Microscopy'],
|
|
71
72
|
},
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
+
if (this.props.schemaValidator) {
|
|
75
|
+
schemaValidate(this.props.files, options).then(this.done)
|
|
76
|
+
} else {
|
|
77
|
+
validate(this.props.files, options).then(this.done)
|
|
78
|
+
}
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
/**
|
|
@@ -115,12 +120,14 @@ UploadValidator.propTypes = {
|
|
|
115
120
|
files: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
116
121
|
next: PropTypes.func,
|
|
117
122
|
reset: PropTypes.func,
|
|
123
|
+
schemaValidator: PropTypes.bool,
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
const UploadIssues = () => (
|
|
121
127
|
<UploaderContext.Consumer>
|
|
122
128
|
{uploader => (
|
|
123
129
|
<UploadValidator
|
|
130
|
+
schemaValidator={uploader.schemaValidator}
|
|
124
131
|
files={uploader.selectedFiles}
|
|
125
132
|
next={() => uploader.setLocation('/upload/metadata')}
|
|
126
133
|
reset={() => uploader.setLocation('/upload')}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import FileSelect from './file-select'
|
|
3
3
|
import UploaderContext from './uploader-context.js'
|
|
4
|
+
import AdminUser from '../authentication/admin-user'
|
|
4
5
|
|
|
5
6
|
const UploadSelect = () => (
|
|
6
7
|
<div>
|
|
@@ -20,6 +21,18 @@ const UploadSelect = () => (
|
|
|
20
21
|
</a>{' '}
|
|
21
22
|
to upload
|
|
22
23
|
<FileSelect onChange={uploader.selectFiles} />
|
|
24
|
+
<AdminUser>
|
|
25
|
+
<input
|
|
26
|
+
type="checkbox"
|
|
27
|
+
id="schema-validator-checkbox"
|
|
28
|
+
onChange={uploader.toggleSchemaValidator}
|
|
29
|
+
defaultChecked={uploader.schemaValidator}
|
|
30
|
+
/>
|
|
31
|
+
<label htmlFor="schema-validator-checkbox">
|
|
32
|
+
{' '}
|
|
33
|
+
Use schema based validator
|
|
34
|
+
</label>
|
|
35
|
+
</AdminUser>
|
|
23
36
|
</div>
|
|
24
37
|
)}
|
|
25
38
|
</UploaderContext.Consumer>
|
|
@@ -67,6 +67,10 @@ export class UploadClient extends React.Component {
|
|
|
67
67
|
failedFiles: new Set(),
|
|
68
68
|
// Abort controller for abandoning the upload
|
|
69
69
|
abortController: null,
|
|
70
|
+
// Enable the new schema validator
|
|
71
|
+
schemaValidator: false,
|
|
72
|
+
// Toggle schemaValidator flag
|
|
73
|
+
toggleSchemaValidator: this.toggleSchemaValidator,
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -80,6 +84,13 @@ export class UploadClient extends React.Component {
|
|
|
80
84
|
this.setState({ location: locationFactory(path) })
|
|
81
85
|
}
|
|
82
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Enable or disable schema based validation
|
|
89
|
+
*/
|
|
90
|
+
toggleSchemaValidator = () => {
|
|
91
|
+
this.setState({ schemaValidator: !this.state.schemaValidator })
|
|
92
|
+
}
|
|
93
|
+
|
|
83
94
|
/**
|
|
84
95
|
* Specify a dataset to resume upload for
|
|
85
96
|
* @param {string} datasetId
|