@openneuro/app 4.15.2-demo.1 → 4.16.1-alpha.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/authentication/regular-user.tsx +20 -0
- package/src/scripts/datalad/dataset/comments-fragments.js +2 -1
- package/src/scripts/dataset/comments/__tests__/__snapshots__/comment.spec.jsx.snap +211 -2
- package/src/scripts/dataset/comments/__tests__/comment.spec.jsx +25 -1
- package/src/scripts/dataset/comments/comment.jsx +3 -3
- package/src/scripts/dataset/dataset-query.jsx +8 -0
- package/src/scripts/dataset/files/file-tree.tsx +5 -3
- package/src/scripts/dataset/files/file.tsx +1 -1
- package/src/scripts/dataset/mutations/__tests__/__snapshots__/delete.spec.jsx.snap +0 -34
- package/src/scripts/dataset/mutations/__tests__/delete-file.spec.jsx +195 -0
- package/src/scripts/dataset/mutations/__tests__/delete.spec.jsx +0 -47
- package/src/scripts/dataset/mutations/delete-file.jsx +94 -21
- package/src/scripts/dataset/routes/delete-page.tsx +31 -21
- package/src/scripts/uploader/upload-issues.jsx +1 -1
- package/src/scripts/users/username.tsx +2 -2
- package/src/scripts/validation/validation-results.issues.jsx +2 -2
- package/src/scripts/validation/validation-results.jsx +1 -1
- package/src/scripts/workers/validate.worker.ts +9 -12
- package/src/scripts/workers/worker-interface.ts +1 -4
- package/vite.config.js +0 -1
- package/src/scripts/datalad/mutations/delete-dir.jsx +0 -43
- package/src/scripts/datalad/mutations/delete-file.jsx +0 -41
- package/src/scripts/dataset/mutations/delete-dir.jsx +0 -43
- package/src/scripts/utils/schema-validator.js +0 -196477
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/app",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.16.1-alpha.0",
|
|
4
4
|
"description": "React JS web frontend for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "public/client.js",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"@emotion/react": "11.6.0",
|
|
21
21
|
"@emotion/styled": "11.6.0",
|
|
22
22
|
"@niivue/niivue": "0.23.1",
|
|
23
|
-
"@openneuro/client": "^4.
|
|
24
|
-
"@openneuro/components": "^4.
|
|
25
|
-
"bids-validator": "1.
|
|
23
|
+
"@openneuro/client": "^4.16.1-alpha.0",
|
|
24
|
+
"@openneuro/components": "^4.16.1-alpha.0",
|
|
25
|
+
"bids-validator": "1.10.0",
|
|
26
26
|
"bytes": "^3.0.0",
|
|
27
27
|
"comlink": "^4.0.5",
|
|
28
28
|
"date-fns": "^2.16.1",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"publishConfig": {
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "e21edfff977cb4d9105517acf85603e9114a8bd2"
|
|
85
85
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useCookies } from 'react-cookie'
|
|
3
|
+
import { getProfile } from './profile.js'
|
|
4
|
+
|
|
5
|
+
interface RegularUserProps {
|
|
6
|
+
children?: React.ReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Render children if this is not an admin user
|
|
11
|
+
*/
|
|
12
|
+
export const RegularUser = ({ children }: RegularUserProps): JSX.Element => {
|
|
13
|
+
const [cookies] = useCookies()
|
|
14
|
+
const profile = getProfile(cookies)
|
|
15
|
+
if (profile?.admin) {
|
|
16
|
+
return null
|
|
17
|
+
} else {
|
|
18
|
+
return <>{children}</>
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,5 +1,210 @@
|
|
|
1
1
|
// Vitest Snapshot v1
|
|
2
2
|
|
|
3
|
+
exports[`Comment component > renders an ORCID user comment 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"asFragment": [Function],
|
|
6
|
+
"baseElement": <body>
|
|
7
|
+
<div>
|
|
8
|
+
<div
|
|
9
|
+
class="comment"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
class="row comment-header"
|
|
13
|
+
>
|
|
14
|
+
By
|
|
15
|
+
Example Exampler
|
|
16
|
+
|
|
17
|
+
<a
|
|
18
|
+
href="https://orcid.org/1234-5678-9101"
|
|
19
|
+
>
|
|
20
|
+
<img
|
|
21
|
+
alt="ORCID logo"
|
|
22
|
+
height="16"
|
|
23
|
+
src="/packages/openneuro-app/src/assets/ORCIDiD_iconvector.svg"
|
|
24
|
+
width="16"
|
|
25
|
+
/>
|
|
26
|
+
</a>
|
|
27
|
+
- almost 2 years ago
|
|
28
|
+
</div>
|
|
29
|
+
<div
|
|
30
|
+
class="row comment-body"
|
|
31
|
+
>
|
|
32
|
+
<div
|
|
33
|
+
class="DraftEditor-root"
|
|
34
|
+
>
|
|
35
|
+
<div
|
|
36
|
+
class="DraftEditor-editorContainer"
|
|
37
|
+
>
|
|
38
|
+
<div
|
|
39
|
+
class="public-DraftEditor-content"
|
|
40
|
+
contenteditable="false"
|
|
41
|
+
spellcheck="false"
|
|
42
|
+
style="outline: none; user-select: text; white-space: pre-wrap; word-wrap: break-word;"
|
|
43
|
+
>
|
|
44
|
+
<div
|
|
45
|
+
data-contents="true"
|
|
46
|
+
>
|
|
47
|
+
<div
|
|
48
|
+
class=""
|
|
49
|
+
data-block="true"
|
|
50
|
+
data-editor="9001"
|
|
51
|
+
data-offset-key="3sm42-0-0"
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
|
|
55
|
+
data-offset-key="3sm42-0-0"
|
|
56
|
+
>
|
|
57
|
+
<span
|
|
58
|
+
data-offset-key="3sm42-0-0"
|
|
59
|
+
>
|
|
60
|
+
<br
|
|
61
|
+
data-text="true"
|
|
62
|
+
/>
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
<div
|
|
73
|
+
class="row replies"
|
|
74
|
+
>
|
|
75
|
+
<div
|
|
76
|
+
class="comment-reply"
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</body>,
|
|
81
|
+
"container": <div>
|
|
82
|
+
<div
|
|
83
|
+
class="comment"
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
class="row comment-header"
|
|
87
|
+
>
|
|
88
|
+
By
|
|
89
|
+
Example Exampler
|
|
90
|
+
|
|
91
|
+
<a
|
|
92
|
+
href="https://orcid.org/1234-5678-9101"
|
|
93
|
+
>
|
|
94
|
+
<img
|
|
95
|
+
alt="ORCID logo"
|
|
96
|
+
height="16"
|
|
97
|
+
src="/packages/openneuro-app/src/assets/ORCIDiD_iconvector.svg"
|
|
98
|
+
width="16"
|
|
99
|
+
/>
|
|
100
|
+
</a>
|
|
101
|
+
- almost 2 years ago
|
|
102
|
+
</div>
|
|
103
|
+
<div
|
|
104
|
+
class="row comment-body"
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
class="DraftEditor-root"
|
|
108
|
+
>
|
|
109
|
+
<div
|
|
110
|
+
class="DraftEditor-editorContainer"
|
|
111
|
+
>
|
|
112
|
+
<div
|
|
113
|
+
class="public-DraftEditor-content"
|
|
114
|
+
contenteditable="false"
|
|
115
|
+
spellcheck="false"
|
|
116
|
+
style="outline: none; user-select: text; white-space: pre-wrap; word-wrap: break-word;"
|
|
117
|
+
>
|
|
118
|
+
<div
|
|
119
|
+
data-contents="true"
|
|
120
|
+
>
|
|
121
|
+
<div
|
|
122
|
+
class=""
|
|
123
|
+
data-block="true"
|
|
124
|
+
data-editor="9001"
|
|
125
|
+
data-offset-key="3sm42-0-0"
|
|
126
|
+
>
|
|
127
|
+
<div
|
|
128
|
+
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
|
|
129
|
+
data-offset-key="3sm42-0-0"
|
|
130
|
+
>
|
|
131
|
+
<span
|
|
132
|
+
data-offset-key="3sm42-0-0"
|
|
133
|
+
>
|
|
134
|
+
<br
|
|
135
|
+
data-text="true"
|
|
136
|
+
/>
|
|
137
|
+
</span>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
<div
|
|
147
|
+
class="row replies"
|
|
148
|
+
>
|
|
149
|
+
<div
|
|
150
|
+
class="comment-reply"
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
</div>,
|
|
154
|
+
"debug": [Function],
|
|
155
|
+
"findAllByAltText": [Function],
|
|
156
|
+
"findAllByDisplayValue": [Function],
|
|
157
|
+
"findAllByLabelText": [Function],
|
|
158
|
+
"findAllByPlaceholderText": [Function],
|
|
159
|
+
"findAllByRole": [Function],
|
|
160
|
+
"findAllByTestId": [Function],
|
|
161
|
+
"findAllByText": [Function],
|
|
162
|
+
"findAllByTitle": [Function],
|
|
163
|
+
"findByAltText": [Function],
|
|
164
|
+
"findByDisplayValue": [Function],
|
|
165
|
+
"findByLabelText": [Function],
|
|
166
|
+
"findByPlaceholderText": [Function],
|
|
167
|
+
"findByRole": [Function],
|
|
168
|
+
"findByTestId": [Function],
|
|
169
|
+
"findByText": [Function],
|
|
170
|
+
"findByTitle": [Function],
|
|
171
|
+
"getAllByAltText": [Function],
|
|
172
|
+
"getAllByDisplayValue": [Function],
|
|
173
|
+
"getAllByLabelText": [Function],
|
|
174
|
+
"getAllByPlaceholderText": [Function],
|
|
175
|
+
"getAllByRole": [Function],
|
|
176
|
+
"getAllByTestId": [Function],
|
|
177
|
+
"getAllByText": [Function],
|
|
178
|
+
"getAllByTitle": [Function],
|
|
179
|
+
"getByAltText": [Function],
|
|
180
|
+
"getByDisplayValue": [Function],
|
|
181
|
+
"getByLabelText": [Function],
|
|
182
|
+
"getByPlaceholderText": [Function],
|
|
183
|
+
"getByRole": [Function],
|
|
184
|
+
"getByTestId": [Function],
|
|
185
|
+
"getByText": [Function],
|
|
186
|
+
"getByTitle": [Function],
|
|
187
|
+
"queryAllByAltText": [Function],
|
|
188
|
+
"queryAllByDisplayValue": [Function],
|
|
189
|
+
"queryAllByLabelText": [Function],
|
|
190
|
+
"queryAllByPlaceholderText": [Function],
|
|
191
|
+
"queryAllByRole": [Function],
|
|
192
|
+
"queryAllByTestId": [Function],
|
|
193
|
+
"queryAllByText": [Function],
|
|
194
|
+
"queryAllByTitle": [Function],
|
|
195
|
+
"queryByAltText": [Function],
|
|
196
|
+
"queryByDisplayValue": [Function],
|
|
197
|
+
"queryByLabelText": [Function],
|
|
198
|
+
"queryByPlaceholderText": [Function],
|
|
199
|
+
"queryByRole": [Function],
|
|
200
|
+
"queryByTestId": [Function],
|
|
201
|
+
"queryByText": [Function],
|
|
202
|
+
"queryByTitle": [Function],
|
|
203
|
+
"rerender": [Function],
|
|
204
|
+
"unmount": [Function],
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
207
|
+
|
|
3
208
|
exports[`Comment component > renders with an empty comment 1`] = `
|
|
4
209
|
{
|
|
5
210
|
"asFragment": [Function],
|
|
@@ -11,7 +216,9 @@ exports[`Comment component > renders with an empty comment 1`] = `
|
|
|
11
216
|
<div
|
|
12
217
|
class="row comment-header"
|
|
13
218
|
>
|
|
14
|
-
By
|
|
219
|
+
By
|
|
220
|
+
Example Exampler
|
|
221
|
+
- almost 2 years ago
|
|
15
222
|
</div>
|
|
16
223
|
<div
|
|
17
224
|
class="row comment-body"
|
|
@@ -72,7 +279,9 @@ exports[`Comment component > renders with an empty comment 1`] = `
|
|
|
72
279
|
<div
|
|
73
280
|
class="row comment-header"
|
|
74
281
|
>
|
|
75
|
-
By
|
|
282
|
+
By
|
|
283
|
+
Example Exampler
|
|
284
|
+
- almost 2 years ago
|
|
76
285
|
</div>
|
|
77
286
|
<div
|
|
78
287
|
class="row comment-body"
|
|
@@ -17,7 +17,31 @@ describe('Comment component', () => {
|
|
|
17
17
|
data={{
|
|
18
18
|
id: '9001',
|
|
19
19
|
text: emptyState,
|
|
20
|
-
user: {
|
|
20
|
+
user: {
|
|
21
|
+
id: '1234',
|
|
22
|
+
email: 'example@example.com',
|
|
23
|
+
name: 'Example Exampler',
|
|
24
|
+
},
|
|
25
|
+
createDate: new Date('2019-04-02T19:56:41.222Z').toISOString(),
|
|
26
|
+
}}
|
|
27
|
+
/>,
|
|
28
|
+
)
|
|
29
|
+
expect(wrapper).toMatchSnapshot()
|
|
30
|
+
})
|
|
31
|
+
it('renders an ORCID user comment', () => {
|
|
32
|
+
formatDistanceToNow.mockReturnValueOnce('almost 2 years')
|
|
33
|
+
|
|
34
|
+
const wrapper = render(
|
|
35
|
+
<Comment
|
|
36
|
+
data={{
|
|
37
|
+
id: '9001',
|
|
38
|
+
text: emptyState,
|
|
39
|
+
user: {
|
|
40
|
+
id: '1234',
|
|
41
|
+
email: 'example@example.com',
|
|
42
|
+
name: 'Example Exampler',
|
|
43
|
+
orcid: '1234-5678-9101',
|
|
44
|
+
},
|
|
21
45
|
createDate: new Date('2019-04-02T19:56:41.222Z').toISOString(),
|
|
22
46
|
}}
|
|
23
47
|
/>,
|
|
@@ -11,6 +11,7 @@ import LoggedIn from '../../authentication/logged-in.jsx'
|
|
|
11
11
|
import { toast } from 'react-toastify'
|
|
12
12
|
import ToastContent from '../../common/partials/toast-content'
|
|
13
13
|
import { Icon } from '@openneuro/components/icon'
|
|
14
|
+
import { Username } from '../../users/username'
|
|
14
15
|
|
|
15
16
|
const Comment = ({ datasetId, data, children }) => {
|
|
16
17
|
const [replyMode, setReplyMode] = useState(false)
|
|
@@ -21,9 +22,8 @@ const Comment = ({ datasetId, data, children }) => {
|
|
|
21
22
|
<>
|
|
22
23
|
<div className="comment">
|
|
23
24
|
<div className="row comment-header">
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)} ago`}
|
|
25
|
+
By <Username user={data.user} />
|
|
26
|
+
{` - ${formatDistanceToNow(parseISO(data.createDate))} ago`}
|
|
27
27
|
</div>
|
|
28
28
|
<div className="row comment-body">
|
|
29
29
|
{editMode ? (
|
|
@@ -162,6 +162,14 @@ export const DatasetQueryHook = ({ datasetId, draft }) => {
|
|
|
162
162
|
if (error.message === 'You do not have access to read this dataset.') {
|
|
163
163
|
return <FourOThreePage />
|
|
164
164
|
} else if (error.message.includes('has been deleted')) {
|
|
165
|
+
for (const err of error.graphQLErrors) {
|
|
166
|
+
if (
|
|
167
|
+
err.extensions.code === 'DELETED_DATASET' &&
|
|
168
|
+
err.extensions.redirect
|
|
169
|
+
) {
|
|
170
|
+
navigate(err.extensions.redirect)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
165
173
|
return <FourOFourPage message={error.message} />
|
|
166
174
|
} else {
|
|
167
175
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import File from './file'
|
|
3
3
|
import UpdateFile from '../mutations/update-file.jsx'
|
|
4
|
-
import
|
|
4
|
+
import DeleteFile from '../mutations/delete-file.jsx'
|
|
5
5
|
import FileTreeUnloadedDirectory from './file-tree-unloaded-directory.jsx'
|
|
6
6
|
import { Media } from '../../styles/media'
|
|
7
7
|
import { AccordionTab } from '@openneuro/components/accordion'
|
|
@@ -91,8 +91,10 @@ const FileTree = ({
|
|
|
91
91
|
directory>
|
|
92
92
|
<i className="fa fa-plus" /> Add Directory
|
|
93
93
|
</UpdateFile>
|
|
94
|
-
{
|
|
95
|
-
|
|
94
|
+
{path === '' ? (
|
|
95
|
+
bulkDeleteButton
|
|
96
|
+
) : (
|
|
97
|
+
<DeleteFile datasetId={datasetId} path={path} filename={name} />
|
|
96
98
|
)}
|
|
97
99
|
</span>
|
|
98
100
|
</Media>
|
|
@@ -117,7 +117,7 @@ const File = ({
|
|
|
117
117
|
datasetPermissions,
|
|
118
118
|
toggleFileToDelete,
|
|
119
119
|
isFileToBeDeleted,
|
|
120
|
-
}: FileProps) => {
|
|
120
|
+
}: FileProps): JSX.Element => {
|
|
121
121
|
const { icon, color } = getFileIcon(filename)
|
|
122
122
|
const snapshotVersionPath = snapshotTag ? `/versions/${snapshotTag}` : ''
|
|
123
123
|
// React route to display the file
|
|
@@ -14,37 +14,3 @@ exports[`DeleteDataset mutation > renders with common props 1`] = `
|
|
|
14
14
|
</span>
|
|
15
15
|
</DocumentFragment>
|
|
16
16
|
`;
|
|
17
|
-
|
|
18
|
-
exports[`DeleteDir mutation > renders with common props 1`] = `
|
|
19
|
-
<DocumentFragment>
|
|
20
|
-
<span
|
|
21
|
-
class="delete-file"
|
|
22
|
-
>
|
|
23
|
-
<div
|
|
24
|
-
class="warn-btn edit-file"
|
|
25
|
-
>
|
|
26
|
-
<span
|
|
27
|
-
class=" "
|
|
28
|
-
data-flow="up"
|
|
29
|
-
data-tooltip="Delete undefined"
|
|
30
|
-
>
|
|
31
|
-
<span
|
|
32
|
-
class="warn-btn-click"
|
|
33
|
-
>
|
|
34
|
-
<button
|
|
35
|
-
aria-label=""
|
|
36
|
-
class="on-button on-button--medium on-button--default btn-warn-component"
|
|
37
|
-
role="button"
|
|
38
|
-
type="button"
|
|
39
|
-
>
|
|
40
|
-
<i
|
|
41
|
-
aria-hidden="true"
|
|
42
|
-
class="fa fa-trash css-1qxtz39"
|
|
43
|
-
/>
|
|
44
|
-
</button>
|
|
45
|
-
</span>
|
|
46
|
-
</span>
|
|
47
|
-
</div>
|
|
48
|
-
</span>
|
|
49
|
-
</DocumentFragment>
|
|
50
|
-
`;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { fileCacheDeleteFilter } from '../delete-file.jsx'
|
|
2
|
+
|
|
3
|
+
describe('DeleteFile mutation', () => {
|
|
4
|
+
describe('fileCacheDeleteFilter', () => {
|
|
5
|
+
it('removes a deleted file', () => {
|
|
6
|
+
expect(
|
|
7
|
+
fileCacheDeleteFilter(
|
|
8
|
+
{
|
|
9
|
+
id: 'DatasetFile:abcdef',
|
|
10
|
+
key: 'cdefgh',
|
|
11
|
+
filename: 'sub-01:anat:sub-01_T1w.nii.gz',
|
|
12
|
+
directory: false,
|
|
13
|
+
},
|
|
14
|
+
'sub-01:anat',
|
|
15
|
+
'sub-01_T1w.nii.gz',
|
|
16
|
+
[],
|
|
17
|
+
),
|
|
18
|
+
).toBe(false)
|
|
19
|
+
})
|
|
20
|
+
it('does not remove a present file', () => {
|
|
21
|
+
expect(
|
|
22
|
+
fileCacheDeleteFilter(
|
|
23
|
+
{
|
|
24
|
+
id: 'DatasetFile:abcdef',
|
|
25
|
+
key: 'cdefgh',
|
|
26
|
+
filename: 'sub-02:anat:sub-02_T1w.nii.gz',
|
|
27
|
+
directory: false,
|
|
28
|
+
},
|
|
29
|
+
'sub-01:anat',
|
|
30
|
+
'sub-01_T1w.nii.gz',
|
|
31
|
+
[],
|
|
32
|
+
),
|
|
33
|
+
).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
it('removes a matching directory', () => {
|
|
36
|
+
expect(
|
|
37
|
+
fileCacheDeleteFilter(
|
|
38
|
+
{
|
|
39
|
+
id: 'DatasetFile:abcdef',
|
|
40
|
+
key: 'cdefgh',
|
|
41
|
+
filename: 'sub-01:anat',
|
|
42
|
+
directory: true,
|
|
43
|
+
},
|
|
44
|
+
'sub-01:anat',
|
|
45
|
+
'',
|
|
46
|
+
[],
|
|
47
|
+
),
|
|
48
|
+
).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
it('removes empty directories with a child being deleted', () => {
|
|
51
|
+
const cachedFileObjects = [
|
|
52
|
+
{
|
|
53
|
+
__typename: 'DatasetFile',
|
|
54
|
+
id: '3d9b15b3ef4e9da06e265e6078d3b4ddf8495102',
|
|
55
|
+
key: 'c2ee90bf6c477b9e808e2b649a9492e947493297',
|
|
56
|
+
filename: 'CHANGES',
|
|
57
|
+
directory: false,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
__typename: 'DatasetFile',
|
|
61
|
+
id: '63888a199a5ce37377b1cd708cda59577dad218f',
|
|
62
|
+
key: 'fa84e5f958ec72d42b3e196e592f6db9f7104b19',
|
|
63
|
+
filename: 'README',
|
|
64
|
+
directory: false,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
__typename: 'DatasetFile',
|
|
68
|
+
id: 'aef1717a00106adc115f64990944d86e154d3e03',
|
|
69
|
+
key: 'e652e8add021fe2684ce2404b431dee4315c9c95',
|
|
70
|
+
filename: 'dataset_description.json',
|
|
71
|
+
directory: false,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
__typename: 'DatasetFile',
|
|
75
|
+
id: '0a2a5d8d72a31f03608db59c4cfd650aba77c363',
|
|
76
|
+
key: 'b08aa0ec5b5e716479824859524a22140fb2af82',
|
|
77
|
+
filename: 'T1w.json',
|
|
78
|
+
directory: false,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
__typename: 'DatasetFile',
|
|
82
|
+
id: 'f682a32c9538082fa6c8ad11e9a536dc07d1d0cf',
|
|
83
|
+
key: '37ecbdc7ab8ffaf2cddecc338092f6679089287d',
|
|
84
|
+
filename: 'participants.tsv',
|
|
85
|
+
directory: false,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
__typename: 'DatasetFile',
|
|
89
|
+
id: 'c2ffc386e99bb26fbfc0d6bb33713b91b95a51f2',
|
|
90
|
+
key: null,
|
|
91
|
+
filename: 'sub-01',
|
|
92
|
+
directory: true,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
__typename: 'DatasetFile',
|
|
96
|
+
id: '141c63f3373f17477c83f42c9fab01e6825052a0',
|
|
97
|
+
key: null,
|
|
98
|
+
filename: 'sub-02',
|
|
99
|
+
directory: true,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
__typename: 'DatasetFile',
|
|
103
|
+
id: '635818b25263badb6d105aab8e33822f54ebbecf',
|
|
104
|
+
key: null,
|
|
105
|
+
filename: 'sub-02:anat',
|
|
106
|
+
directory: true,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
__typename: 'DatasetFile',
|
|
110
|
+
id: 'b6f937773aa2130aa9d06fc3024cd1b150baa70b',
|
|
111
|
+
key: 'SHA256E-s311112--c3527d7944a9619afb57863a34e6af7ec3fe4f108e56c860d9e700699ff806fb.nii.gz',
|
|
112
|
+
filename: 'sub-02:anat:sub-02_T1w.nii.gz',
|
|
113
|
+
directory: false,
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
expect(
|
|
117
|
+
fileCacheDeleteFilter(
|
|
118
|
+
{
|
|
119
|
+
id: '141c63f3373f17477c83f42c9fab01e6825052a0',
|
|
120
|
+
key: null,
|
|
121
|
+
filename: 'sub-02',
|
|
122
|
+
directory: true,
|
|
123
|
+
},
|
|
124
|
+
'sub-02:anat',
|
|
125
|
+
'sub-02_T1w.nii.gz',
|
|
126
|
+
cachedFileObjects,
|
|
127
|
+
),
|
|
128
|
+
).toBe(false)
|
|
129
|
+
expect(
|
|
130
|
+
fileCacheDeleteFilter(
|
|
131
|
+
{
|
|
132
|
+
id: '635818b25263badb6d105aab8e33822f54ebbecf',
|
|
133
|
+
key: null,
|
|
134
|
+
filename: 'sub-02:anat',
|
|
135
|
+
directory: true,
|
|
136
|
+
},
|
|
137
|
+
'sub-02:anat',
|
|
138
|
+
'sub-02_T1w.nii.gz',
|
|
139
|
+
cachedFileObjects,
|
|
140
|
+
),
|
|
141
|
+
).toBe(false)
|
|
142
|
+
expect(
|
|
143
|
+
fileCacheDeleteFilter(
|
|
144
|
+
{
|
|
145
|
+
id: 'b6f937773aa2130aa9d06fc3024cd1b150baa70b',
|
|
146
|
+
key: 'SHA256E-s311112--c3527d7944a9619afb57863a34e6af7ec3fe4f108e56c860d9e700699ff806fb.nii.gz',
|
|
147
|
+
filename: 'sub-02:anat:sub-02_T1w.nii.gz',
|
|
148
|
+
directory: false,
|
|
149
|
+
},
|
|
150
|
+
'sub-02:anat',
|
|
151
|
+
'sub-02_T1w.nii.gz',
|
|
152
|
+
cachedFileObjects,
|
|
153
|
+
),
|
|
154
|
+
).toBe(false)
|
|
155
|
+
})
|
|
156
|
+
it('does not remove non-empty directories with a child being deleted', () => {
|
|
157
|
+
expect(
|
|
158
|
+
fileCacheDeleteFilter(
|
|
159
|
+
{
|
|
160
|
+
id: 'DatasetFile:abcdef',
|
|
161
|
+
key: 'cdefgh',
|
|
162
|
+
filename: 'sub-02:anat',
|
|
163
|
+
directory: true,
|
|
164
|
+
},
|
|
165
|
+
'',
|
|
166
|
+
'sub-02:anat:sub-02_T1w.json',
|
|
167
|
+
[
|
|
168
|
+
{
|
|
169
|
+
id: 'DatasetFile:123456',
|
|
170
|
+
key: 'cdefgh',
|
|
171
|
+
filename: 'sub-02:anat:sub-02_T1w.nii.gz',
|
|
172
|
+
directory: false,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
),
|
|
176
|
+
).toBe(true)
|
|
177
|
+
})
|
|
178
|
+
it('does not remove directories that are empty but not having a child deleted', () => {
|
|
179
|
+
// This is also false because the directory has no files in cachedFileObjects
|
|
180
|
+
expect(
|
|
181
|
+
fileCacheDeleteFilter(
|
|
182
|
+
{
|
|
183
|
+
id: 'DatasetFile:abcdef',
|
|
184
|
+
key: 'cdefgh',
|
|
185
|
+
filename: 'sub-02:anat',
|
|
186
|
+
directory: true,
|
|
187
|
+
},
|
|
188
|
+
'sub-01:anat',
|
|
189
|
+
'',
|
|
190
|
+
[],
|
|
191
|
+
),
|
|
192
|
+
).toBe(true)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
})
|
|
@@ -2,10 +2,8 @@ import React from 'react'
|
|
|
2
2
|
import { render, fireEvent, screen } from '@testing-library/react'
|
|
3
3
|
import { MockedProvider } from '@apollo/client/testing'
|
|
4
4
|
import DeleteDataset, { DELETE_DATASET } from '../delete.jsx'
|
|
5
|
-
import DeleteDir, { DELETE_FILES } from '../delete-dir.jsx'
|
|
6
5
|
|
|
7
6
|
const datasetId = 'ds999999'
|
|
8
|
-
const path = 'sub-99'
|
|
9
7
|
|
|
10
8
|
const deleteDatasetMock = {
|
|
11
9
|
request: {
|
|
@@ -20,19 +18,6 @@ const deleteDatasetMock = {
|
|
|
20
18
|
})),
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
const deleteDirMock = {
|
|
24
|
-
request: {
|
|
25
|
-
query: DELETE_FILES,
|
|
26
|
-
variables: {
|
|
27
|
-
datasetId,
|
|
28
|
-
files: [{ path: 'sub-99' }],
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
newData: vi.fn(() => ({
|
|
32
|
-
data: {},
|
|
33
|
-
})),
|
|
34
|
-
}
|
|
35
|
-
|
|
36
21
|
describe('DeleteDataset mutation', () => {
|
|
37
22
|
it('renders with common props', () => {
|
|
38
23
|
const { asFragment } = render(
|
|
@@ -43,35 +28,3 @@ describe('DeleteDataset mutation', () => {
|
|
|
43
28
|
expect(asFragment()).toMatchSnapshot()
|
|
44
29
|
})
|
|
45
30
|
})
|
|
46
|
-
|
|
47
|
-
describe('DeleteDir mutation', () => {
|
|
48
|
-
it('renders with common props', () => {
|
|
49
|
-
const { asFragment } = render(
|
|
50
|
-
<MockedProvider mocks={[deleteDirMock]} addTypename={false}>
|
|
51
|
-
<DeleteDir
|
|
52
|
-
datasetId="ds002"
|
|
53
|
-
fileTree={{
|
|
54
|
-
files: [],
|
|
55
|
-
directories: [],
|
|
56
|
-
path: '',
|
|
57
|
-
}}
|
|
58
|
-
/>
|
|
59
|
-
</MockedProvider>,
|
|
60
|
-
)
|
|
61
|
-
expect(asFragment()).toMatchSnapshot()
|
|
62
|
-
})
|
|
63
|
-
it('fires the correct mutation', async () => {
|
|
64
|
-
render(
|
|
65
|
-
<MockedProvider mocks={[deleteDirMock]} addTypename={false}>
|
|
66
|
-
<DeleteDir {...{ datasetId, path }} />
|
|
67
|
-
</MockedProvider>,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
// click "Delete" button
|
|
71
|
-
await fireEvent.click(screen.getByRole('button'))
|
|
72
|
-
// confirm delete
|
|
73
|
-
await fireEvent.click(screen.getByLabelText('confirm'))
|
|
74
|
-
|
|
75
|
-
expect(deleteDirMock.newData).toHaveBeenCalled()
|
|
76
|
-
})
|
|
77
|
-
})
|