@openneuro/app 4.35.0-alpha.0 → 4.35.0-alpha.1
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 +3 -3
- package/src/scripts/components/scss/upload-modal.scss +6 -0
- package/src/scripts/dataset/fragments/__tests__/dataset-history.spec.tsx +155 -0
- package/src/scripts/dataset/fragments/dataset-history.jsx +6 -7
- package/src/scripts/errors/errorRoute.tsx +2 -0
- package/src/scripts/errors/orcid/email-warning.tsx +21 -0
- package/src/scripts/search/search-container.tsx +2 -3
- package/src/scripts/search/search-params-ctx.tsx +6 -3
- package/src/scripts/search/use-search-results.tsx +1 -1
- package/src/scripts/uploader/file-select.tsx +3 -1
- package/src/scripts/uploader/upload-select.jsx +40 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/app",
|
|
3
|
-
"version": "4.35.0-alpha.
|
|
3
|
+
"version": "4.35.0-alpha.1",
|
|
4
4
|
"description": "React JS web frontend for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "public/client.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@bids/validator": "npm:@jsr/bids__validator@^2.0.3",
|
|
20
20
|
"@emotion/react": "11.11.1",
|
|
21
21
|
"@emotion/styled": "11.11.0",
|
|
22
|
-
"@niivue/niivue": "0.
|
|
22
|
+
"@niivue/niivue": "0.57.0",
|
|
23
23
|
"@openneuro/components": "^4.33.4",
|
|
24
24
|
"@sentry/react": "^8.25.0",
|
|
25
25
|
"@tanstack/react-table": "^8.9.3",
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"publishConfig": {
|
|
76
76
|
"access": "public"
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "ac9c013877e5d9c1fa9615a177f79e0da0747f84"
|
|
79
79
|
}
|
|
@@ -146,6 +146,12 @@
|
|
|
146
146
|
&:hover {
|
|
147
147
|
background-color: var(--current-theme-primary-hover);
|
|
148
148
|
}
|
|
149
|
+
&.disabled {
|
|
150
|
+
background-color: $rock;
|
|
151
|
+
&:hover {
|
|
152
|
+
background-color: $rock;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
149
155
|
}
|
|
150
156
|
.fileupload-btn .multifile-select-btn {
|
|
151
157
|
opacity: 0;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { render, screen } from "@testing-library/react"
|
|
3
|
+
import { MockedProvider } from "@apollo/client/testing"
|
|
4
|
+
import { DatasetHistory, GET_HISTORY } from "../dataset-history"
|
|
5
|
+
|
|
6
|
+
describe("DatasetHistory", () => {
|
|
7
|
+
it("renders an example history correctly", async () => {
|
|
8
|
+
const dataset = {
|
|
9
|
+
id: "ds000001",
|
|
10
|
+
name: "Test Dataset",
|
|
11
|
+
created: "2023-01-01T00:00:00.000Z",
|
|
12
|
+
downloads: 0,
|
|
13
|
+
views: 0,
|
|
14
|
+
stars: 0,
|
|
15
|
+
size: 0,
|
|
16
|
+
history: [
|
|
17
|
+
{
|
|
18
|
+
id: "adbafb8cc26558e1fe2be02fa782bf9f1a6c2556",
|
|
19
|
+
date: "2023-01-01T00:00:00.000Z",
|
|
20
|
+
authorName: "Test Author",
|
|
21
|
+
authorEmail: "test@example.com",
|
|
22
|
+
references: "",
|
|
23
|
+
message: "Initial commit",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "adbafb8cc26558e1fe2be02fa782bf9f1a6c0313",
|
|
27
|
+
date: "2023-01-02T00:00:00.000Z",
|
|
28
|
+
authorName: "Test Author",
|
|
29
|
+
authorEmail: "test@example.com",
|
|
30
|
+
references: "1.0.0",
|
|
31
|
+
message: "Test snapshot",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
authors: [],
|
|
35
|
+
editors: [],
|
|
36
|
+
public: true,
|
|
37
|
+
uploader: null,
|
|
38
|
+
latestSnapshot: null,
|
|
39
|
+
relatedDatasets: [],
|
|
40
|
+
mriqcResults: null,
|
|
41
|
+
tasks: [],
|
|
42
|
+
modalities: [],
|
|
43
|
+
datasetSummary: null,
|
|
44
|
+
datasetDescription: null,
|
|
45
|
+
readme: null,
|
|
46
|
+
license: null,
|
|
47
|
+
funding: null,
|
|
48
|
+
acknowledgements: null,
|
|
49
|
+
howToAcknowledge: null,
|
|
50
|
+
ethicsApprovals: [],
|
|
51
|
+
publications: [],
|
|
52
|
+
datasetMetadata: [],
|
|
53
|
+
changelog: null,
|
|
54
|
+
issues: [],
|
|
55
|
+
starred: false,
|
|
56
|
+
followers: [],
|
|
57
|
+
hasOpenIssues: false,
|
|
58
|
+
createdAt: "2023-01-01T00:00:00.000Z",
|
|
59
|
+
updatedAt: "2023-01-01T00:00:00.000Z",
|
|
60
|
+
uploaderId: null,
|
|
61
|
+
orcid: null,
|
|
62
|
+
userId: null,
|
|
63
|
+
user: null,
|
|
64
|
+
isPrivate: false,
|
|
65
|
+
onboarded: false,
|
|
66
|
+
worker: 0,
|
|
67
|
+
__typename: "Dataset",
|
|
68
|
+
}
|
|
69
|
+
const mocks = [
|
|
70
|
+
{
|
|
71
|
+
request: {
|
|
72
|
+
query: GET_HISTORY,
|
|
73
|
+
variables: { datasetId: dataset.id },
|
|
74
|
+
},
|
|
75
|
+
result: {
|
|
76
|
+
data: {
|
|
77
|
+
dataset,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
await render(
|
|
83
|
+
<MockedProvider mocks={mocks}>
|
|
84
|
+
<DatasetHistory datasetId={dataset.id} />
|
|
85
|
+
</MockedProvider>,
|
|
86
|
+
)
|
|
87
|
+
expect(await screen.findByText("Initial commit")).toBeInTheDocument()
|
|
88
|
+
expect(await screen.findByText("Test snapshot")).toBeInTheDocument()
|
|
89
|
+
})
|
|
90
|
+
it("renders correctly when dataset.history is null", async () => {
|
|
91
|
+
const dataset = {
|
|
92
|
+
id: "ds000001",
|
|
93
|
+
name: "Test Dataset",
|
|
94
|
+
created: "2023-01-01T00:00:00.000Z",
|
|
95
|
+
downloads: 0,
|
|
96
|
+
views: 0,
|
|
97
|
+
stars: 0,
|
|
98
|
+
size: 0,
|
|
99
|
+
history: null,
|
|
100
|
+
authors: [],
|
|
101
|
+
editors: [],
|
|
102
|
+
public: true,
|
|
103
|
+
uploader: null,
|
|
104
|
+
latestSnapshot: null,
|
|
105
|
+
relatedDatasets: [],
|
|
106
|
+
mriqcResults: null,
|
|
107
|
+
tasks: [],
|
|
108
|
+
modalities: [],
|
|
109
|
+
datasetSummary: null,
|
|
110
|
+
datasetDescription: null,
|
|
111
|
+
readme: null,
|
|
112
|
+
license: null,
|
|
113
|
+
funding: null,
|
|
114
|
+
acknowledgements: null,
|
|
115
|
+
howToAcknowledge: null,
|
|
116
|
+
ethicsApprovals: [],
|
|
117
|
+
publications: [],
|
|
118
|
+
datasetMetadata: [],
|
|
119
|
+
changelog: null,
|
|
120
|
+
issues: [],
|
|
121
|
+
starred: false,
|
|
122
|
+
followers: [],
|
|
123
|
+
hasOpenIssues: false,
|
|
124
|
+
createdAt: "2023-01-01T00:00:00.000Z",
|
|
125
|
+
updatedAt: "2023-01-01T00:00:00.000Z",
|
|
126
|
+
uploaderId: null,
|
|
127
|
+
orcid: null,
|
|
128
|
+
userId: null,
|
|
129
|
+
user: null,
|
|
130
|
+
isPrivate: false,
|
|
131
|
+
onboarded: false,
|
|
132
|
+
worker: 0,
|
|
133
|
+
__typename: "Dataset",
|
|
134
|
+
}
|
|
135
|
+
const mocks = [
|
|
136
|
+
{
|
|
137
|
+
request: {
|
|
138
|
+
query: GET_HISTORY,
|
|
139
|
+
variables: { datasetId: dataset.id },
|
|
140
|
+
},
|
|
141
|
+
result: {
|
|
142
|
+
data: {
|
|
143
|
+
dataset,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
]
|
|
148
|
+
await render(
|
|
149
|
+
<MockedProvider mocks={mocks}>
|
|
150
|
+
<DatasetHistory datasetId={dataset.id} />
|
|
151
|
+
</MockedProvider>,
|
|
152
|
+
)
|
|
153
|
+
expect(await screen.findByText("No history available")).toBeInTheDocument()
|
|
154
|
+
})
|
|
155
|
+
})
|
|
@@ -2,10 +2,9 @@ import React from "react"
|
|
|
2
2
|
import PropTypes from "prop-types"
|
|
3
3
|
import styled from "@emotion/styled"
|
|
4
4
|
import { gql, useQuery } from "@apollo/client"
|
|
5
|
-
|
|
6
5
|
import Revalidate from "../mutations/revalidate.jsx"
|
|
7
6
|
|
|
8
|
-
const GET_HISTORY = gql`
|
|
7
|
+
export const GET_HISTORY = gql`
|
|
9
8
|
query getHistory($datasetId: ID!) {
|
|
10
9
|
dataset(id: $datasetId) {
|
|
11
10
|
id
|
|
@@ -29,16 +28,16 @@ const DatasetHistoryTable = styled.div`
|
|
|
29
28
|
.row:nth-of-type(2n) {
|
|
30
29
|
padding-top: 1em;
|
|
31
30
|
}
|
|
32
|
-
.row:nth-of-type(2n
|
|
31
|
+
.row:nth-of-type(2n+1) {
|
|
33
32
|
padding-bottom: 1em;
|
|
34
33
|
}
|
|
35
34
|
.row:nth-of-type(4n),
|
|
36
|
-
.row:nth-of-type(4n
|
|
35
|
+
.row:nth-of-type(4n+1) {
|
|
37
36
|
background: #f4f4f4;
|
|
38
37
|
}
|
|
39
38
|
`
|
|
40
39
|
|
|
41
|
-
const DatasetHistory = ({ datasetId }) => {
|
|
40
|
+
export const DatasetHistory = ({ datasetId }) => {
|
|
42
41
|
const { loading, data } = useQuery(GET_HISTORY, {
|
|
43
42
|
variables: { datasetId },
|
|
44
43
|
errorPolicy: "all",
|
|
@@ -58,7 +57,7 @@ const DatasetHistory = ({ datasetId }) => {
|
|
|
58
57
|
<h4 className="col-lg col col-2">References</h4>
|
|
59
58
|
<h4 className="col-lg col col-2 text--right">Action</h4>
|
|
60
59
|
</div>
|
|
61
|
-
{data.dataset
|
|
60
|
+
{data.dataset?.history?.map((commit) => (
|
|
62
61
|
<React.Fragment key={commit.id}>
|
|
63
62
|
<div className="grid faux-table">
|
|
64
63
|
<div className="commit col-lg col col-2">
|
|
@@ -83,7 +82,7 @@ const DatasetHistory = ({ datasetId }) => {
|
|
|
83
82
|
<div className="col-lg col col-12">{commit.message}</div>
|
|
84
83
|
</div>
|
|
85
84
|
</React.Fragment>
|
|
86
|
-
))}
|
|
85
|
+
)) || "No history available"}
|
|
87
86
|
</DatasetHistoryTable>
|
|
88
87
|
</div>
|
|
89
88
|
)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import React from "react"
|
|
5
5
|
import { Route, Routes } from "react-router-dom"
|
|
6
6
|
import OrcidGeneral from "./orcid/general.jsx"
|
|
7
|
+
import { OrcidEmailWarning } from "./orcid/email-warning.js"
|
|
7
8
|
import FourOFourPage from "./404page.js"
|
|
8
9
|
|
|
9
10
|
function ErrorRoute() {
|
|
@@ -12,6 +13,7 @@ function ErrorRoute() {
|
|
|
12
13
|
<div className="panel">
|
|
13
14
|
<Routes>
|
|
14
15
|
<Route path="orcid" element={<OrcidGeneral />} />
|
|
16
|
+
<Route path="email-warning" element={<OrcidEmailWarning />} />
|
|
15
17
|
<Route path="*" element={<FourOFourPage />} />
|
|
16
18
|
</Routes>
|
|
17
19
|
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
|
|
3
|
+
export const OrcidEmailWarning = () => (
|
|
4
|
+
<div className="panel-heading">
|
|
5
|
+
<h2>No Email Provided</h2>
|
|
6
|
+
<p>
|
|
7
|
+
To make contributions to OpenNeuro, please provide a contact email
|
|
8
|
+
address.
|
|
9
|
+
</p>
|
|
10
|
+
<p>
|
|
11
|
+
Verify an email and make it available either publicly or to trusted
|
|
12
|
+
institutions to make contributions to OpenNeuro. See our{" "}
|
|
13
|
+
<a href="https://docs.openneuro.org/orcid.html#enabling-trusted-access-to-emails">
|
|
14
|
+
ORCID documentation
|
|
15
|
+
</a>{" "}
|
|
16
|
+
for detailed instructions.
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
export default OrcidEmailWarning
|
|
@@ -236,9 +236,8 @@ const SearchContainer: FC<SearchContainerProps> = ({ portalContent }) => {
|
|
|
236
236
|
/>
|
|
237
237
|
{/* TODO: make div below into display component. */}
|
|
238
238
|
<div className="grid grid-nogutter" style={{ width: "100%" }}>
|
|
239
|
-
{resultsList.length > 0
|
|
240
|
-
|
|
241
|
-
: (
|
|
239
|
+
{hasNextPage && resultsList.length > 0 &&
|
|
240
|
+
(
|
|
242
241
|
<div className="col col-12 load-more m-t-10">
|
|
243
242
|
<Button label="Load More" onClick={loadMore} />
|
|
244
243
|
</div>
|
|
@@ -24,7 +24,7 @@ export const SearchParamsProvider: React.FC<SearchParamsProviderProps> = ({
|
|
|
24
24
|
Sentry.addBreadcrumb({
|
|
25
25
|
category: "routing",
|
|
26
26
|
message: "No query found in URL. Using initialSearchParams.",
|
|
27
|
-
level: "info"
|
|
27
|
+
level: "info",
|
|
28
28
|
})
|
|
29
29
|
}
|
|
30
30
|
} catch (err) {
|
|
@@ -79,8 +79,11 @@ export const removeFilterItem = (setSearchParams) => (param, value) => {
|
|
|
79
79
|
/* Handle simple filter resets. */
|
|
80
80
|
case "datasetType_selected":
|
|
81
81
|
// when datasetType is unset, unset datasetStatus as well
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
setSearchParams((prevState) => ({
|
|
83
|
+
...prevState,
|
|
84
|
+
[param]: initialSearchParams[param],
|
|
85
|
+
"datasetStatus_selected": initialSearchParams["datasetStatus_selected"],
|
|
86
|
+
}))
|
|
84
87
|
break
|
|
85
88
|
case "modality_selected":
|
|
86
89
|
case "brain_initiative":
|
|
@@ -24,7 +24,9 @@ class Upload extends React.Component<UploadProps> {
|
|
|
24
24
|
const text = this.props.resume ? "Resume" : "Select folder"
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
|
-
<div
|
|
27
|
+
<div
|
|
28
|
+
className={"fileupload-btn" + (this.props.disabled ? " disabled" : "")}
|
|
29
|
+
>
|
|
28
30
|
<span>
|
|
29
31
|
{icon}
|
|
30
32
|
{text}
|
|
@@ -1,30 +1,46 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import FileSelect from "./file-select"
|
|
3
3
|
import UploaderContext from "./uploader-context.js"
|
|
4
|
+
import { useUser } from "../queries/user"
|
|
4
5
|
|
|
5
|
-
const UploadSelect = () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
6
|
+
const UploadSelect = () => {
|
|
7
|
+
const { user, loading, error } = useUser()
|
|
8
|
+
const disabled = loading || Boolean(error) || !user || !user.email
|
|
9
|
+
const noEmail = !user.email
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<UploaderContext.Consumer>
|
|
13
|
+
{(uploader) => (
|
|
14
|
+
<div className="message fade-in">
|
|
15
|
+
<p>
|
|
16
|
+
To protect the privacy of the individuals who have been scanned,
|
|
17
|
+
we require that all scan data be defaced before publishing a
|
|
18
|
+
dataset.
|
|
19
|
+
</p>
|
|
20
|
+
Select a{" "}
|
|
21
|
+
<a
|
|
22
|
+
href="http://bids.neuroimaging.io"
|
|
23
|
+
target="_blank"
|
|
24
|
+
rel="noopener noreferrer"
|
|
25
|
+
>
|
|
26
|
+
BIDS dataset
|
|
27
|
+
</a>{" "}
|
|
28
|
+
to upload
|
|
29
|
+
<FileSelect onChange={uploader.selectFiles} disabled={disabled} />
|
|
30
|
+
{noEmail && (
|
|
31
|
+
<p>
|
|
32
|
+
Connect a contact email to upload. See our{" "}
|
|
33
|
+
<a href="https://docs.openneuro.org/orcid.html#enabling-trusted-access-to-emails">
|
|
34
|
+
ORCID documentation
|
|
35
|
+
</a>{" "}
|
|
36
|
+
for instructions.
|
|
37
|
+
</p>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
41
|
+
</UploaderContext.Consumer>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
29
45
|
|
|
30
46
|
export default UploadSelect
|