@openneuro/app 4.47.7 → 5.0.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 +2 -2
- package/src/client.jsx +3 -0
- package/src/scripts/contributors/contributor.tsx +3 -2
- package/src/scripts/contributors/contributors-list.tsx +0 -1
- package/src/scripts/datalad/dataset/dataset-query-fragments.js +0 -2
- package/src/scripts/datalad/mutations/delete-comment.jsx +1 -1
- package/src/scripts/dataset/__tests__/dataset-canonical-url.spec.ts +20 -0
- package/src/scripts/dataset/components/dataset-event-item.tsx +4 -4
- package/src/scripts/dataset/dataset-canonical-url.ts +14 -0
- package/src/scripts/dataset/dataset-query.jsx +8 -0
- package/src/scripts/dataset/download/__tests__/download-script.spec.tsx +1 -1
- package/src/scripts/dataset/download/download-script.tsx +21 -10
- package/src/scripts/dataset/files/__tests__/file-tree-unloaded-directory.spec.jsx +4 -4
- package/src/scripts/dataset/files/file-tree-unloaded-directory.jsx +2 -5
- package/src/scripts/dataset/files/file-tree.tsx +1 -1
- package/src/scripts/dataset/mutations/delete-file.jsx +11 -16
- package/src/scripts/dataset/mutations/hold-deletion.tsx +57 -0
- package/src/scripts/dataset/routes/__tests__/snapshot.spec.tsx +56 -0
- package/src/scripts/dataset/routes/admin-datalad.jsx +10 -0
- package/src/scripts/dataset/routes/snapshot.tsx +8 -2
- package/src/scripts/pages/front-page/aggregate-queries/use-publicDatasets-count.ts +2 -4
- package/src/scripts/queries/dataset.ts +1 -1
- package/src/scripts/queries/datasetEvents.ts +2 -2
- package/src/scripts/queries/user.ts +1 -3
- package/src/scripts/search/inputs/__tests__/sort-by-select.spec.tsx +4 -26
- package/src/scripts/search/inputs/sort-by-select.tsx +6 -6
- package/src/scripts/search/use-search-results.tsx +38 -256
- package/src/scripts/types/event-types.ts +21 -8
- package/src/scripts/users/__tests__/user-routes.spec.tsx +2 -11
- package/src/scripts/users/notifications/user-notification-accordion-actions.tsx +5 -5
- package/src/scripts/users/notifications/user-notification-accordion-header.tsx +4 -1
- package/src/scripts/users/notifications/user-notification-accordion.tsx +12 -5
- package/src/scripts/users/notifications/user-notification-reason-input.tsx +6 -3
- package/src/scripts/users/notifications/user-notifications-accordion-body.tsx +3 -3
- package/src/scripts/users/user-datasets-view.tsx +83 -164
- package/src/scripts/datalad/dataset/comments-fragments.js +0 -22
- package/src/scripts/datalad/mutations/follow.jsx +0 -54
- package/src/scripts/datalad/mutations/publish.jsx +0 -58
- package/src/scripts/datalad/mutations/star.jsx +0 -54
- package/src/scripts/pages/admin/user-fragment.ts +0 -21
- package/src/scripts/search/es-query-builders.ts +0 -107
|
@@ -9,36 +9,51 @@ import { Loading } from "../components/loading/Loading"
|
|
|
9
9
|
import type { Dataset, UserDatasetsViewProps } from "../types/user-types"
|
|
10
10
|
import styles from "./scss/datasetcard.module.scss"
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
interface SearchInput {
|
|
13
|
+
keywords?: string[]
|
|
14
|
+
userId?: string
|
|
15
|
+
publicOnly?: boolean
|
|
16
|
+
sortBy?: string
|
|
17
|
+
}
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
| { match_all: Record<string, never> }
|
|
40
|
-
)[]
|
|
19
|
+
const buildSearchInput = (
|
|
20
|
+
searchQuery: string,
|
|
21
|
+
publicFilter: string,
|
|
22
|
+
userId: string | undefined,
|
|
23
|
+
hasEdit: boolean,
|
|
24
|
+
sortBy: string | undefined,
|
|
25
|
+
): SearchInput => {
|
|
26
|
+
const input: SearchInput = {}
|
|
27
|
+
|
|
28
|
+
if (userId) {
|
|
29
|
+
input.userId = userId
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (hasEdit) {
|
|
33
|
+
if (publicFilter === "public") {
|
|
34
|
+
input.publicOnly = true
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
input.publicOnly = true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (searchQuery) {
|
|
41
|
+
input.keywords = [searchQuery]
|
|
41
42
|
}
|
|
43
|
+
|
|
44
|
+
if (sortBy) {
|
|
45
|
+
input.sortBy = sortBy
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return input
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const SORT_MAP: Record<string, string | undefined> = {
|
|
52
|
+
"name-asc": "name_asc",
|
|
53
|
+
"name-desc": "name_desc",
|
|
54
|
+
"date-newest": "newest",
|
|
55
|
+
"date-oldest": "oldest",
|
|
56
|
+
"date-updated": "last_updated",
|
|
42
57
|
}
|
|
43
58
|
|
|
44
59
|
export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
@@ -52,81 +67,12 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
52
67
|
const [loadMoreLoading, setLoadMoreLoading] = useState(false)
|
|
53
68
|
const [cursor, setCursor] = useState<string | null>(null)
|
|
54
69
|
const [hasNextPage, setHasNextPage] = useState(false)
|
|
55
|
-
const [sortBy, setSortBy] = useState<SortByType>(null)
|
|
56
70
|
const loadAmount = 26
|
|
57
71
|
|
|
58
|
-
const
|
|
59
|
-
(
|
|
60
|
-
currentSearchQuery: string,
|
|
61
|
-
currentPublicFilter: string,
|
|
62
|
-
): ElasticsearchQuery => {
|
|
63
|
-
const baseQuery: ElasticsearchQuery = {
|
|
64
|
-
bool: {
|
|
65
|
-
filter: [],
|
|
66
|
-
must: [],
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (orcidUser?.id) {
|
|
71
|
-
baseQuery.bool.filter.push({
|
|
72
|
-
terms: {
|
|
73
|
-
"permissions.userPermissions.user.id": [orcidUser.id],
|
|
74
|
-
},
|
|
75
|
-
})
|
|
76
|
-
}
|
|
72
|
+
const sortByValue = SORT_MAP[sortOrder]
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
baseQuery.bool.filter.push({ term: { public: true } })
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
baseQuery.bool.filter.push({ term: { public: true } })
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (currentSearchQuery) {
|
|
87
|
-
baseQuery.bool.must.push({
|
|
88
|
-
bool: {
|
|
89
|
-
should: [
|
|
90
|
-
{
|
|
91
|
-
multi_match: {
|
|
92
|
-
query: currentSearchQuery,
|
|
93
|
-
fields: [
|
|
94
|
-
"id^3",
|
|
95
|
-
"name^3",
|
|
96
|
-
"description.Name^3",
|
|
97
|
-
"description.Authors^3",
|
|
98
|
-
"latestSnapshot.description.Name",
|
|
99
|
-
"latestSnapshot.description.Authors",
|
|
100
|
-
"latestSnapshot.readme",
|
|
101
|
-
],
|
|
102
|
-
fuzziness: 1,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
prefix: {
|
|
107
|
-
name: currentSearchQuery.toLowerCase(),
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
prefix: {
|
|
112
|
-
"description.Name": currentSearchQuery.toLowerCase(),
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
minimum_should_match: 1,
|
|
117
|
-
},
|
|
118
|
-
})
|
|
119
|
-
} else {
|
|
120
|
-
baseQuery.bool.must.push({ match_all: {} })
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return baseQuery
|
|
124
|
-
},
|
|
125
|
-
[orcidUser?.id, hasEdit],
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
const [elasticsearchQuery, setElasticsearchQuery] = useState(() =>
|
|
129
|
-
generateElasticsearchQuery("", "all")
|
|
74
|
+
const [searchInput, setSearchInput] = useState(() =>
|
|
75
|
+
buildSearchInput("", "all", orcidUser?.id, hasEdit, sortByValue)
|
|
130
76
|
)
|
|
131
77
|
|
|
132
78
|
const { data, loading, error, fetchMore, refetch } = useQuery(
|
|
@@ -134,8 +80,7 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
134
80
|
{
|
|
135
81
|
variables: {
|
|
136
82
|
first: loadAmount,
|
|
137
|
-
query:
|
|
138
|
-
sortBy: sortBy,
|
|
83
|
+
query: searchInput,
|
|
139
84
|
cursor: null,
|
|
140
85
|
allDatasets: true,
|
|
141
86
|
datasetStatus: undefined,
|
|
@@ -161,89 +106,63 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
161
106
|
(newSearchQuery: string, currentPublicFilter: string) => {
|
|
162
107
|
setSearchQuery(newSearchQuery)
|
|
163
108
|
setPublicFilter(currentPublicFilter)
|
|
164
|
-
const
|
|
109
|
+
const newInput = buildSearchInput(
|
|
165
110
|
newSearchQuery,
|
|
166
111
|
currentPublicFilter,
|
|
112
|
+
orcidUser?.id,
|
|
113
|
+
hasEdit,
|
|
114
|
+
sortByValue,
|
|
167
115
|
)
|
|
168
|
-
|
|
116
|
+
setSearchInput(newInput)
|
|
169
117
|
refetch({
|
|
170
|
-
query:
|
|
118
|
+
query: newInput,
|
|
171
119
|
cursor: null,
|
|
172
|
-
sortBy: sortBy,
|
|
173
120
|
datasetStatus: undefined,
|
|
174
121
|
})
|
|
175
122
|
},
|
|
176
|
-
[
|
|
177
|
-
generateElasticsearchQuery,
|
|
178
|
-
refetch,
|
|
179
|
-
setSearchQuery,
|
|
180
|
-
setPublicFilter,
|
|
181
|
-
setElasticsearchQuery,
|
|
182
|
-
sortBy,
|
|
183
|
-
hasEdit,
|
|
184
|
-
orcidUser?.id,
|
|
185
|
-
],
|
|
123
|
+
[refetch, sortByValue, hasEdit, orcidUser?.id],
|
|
186
124
|
)
|
|
187
125
|
|
|
188
126
|
const handlePublicFilterChange = useCallback(
|
|
189
127
|
(newPublicFilter) => {
|
|
190
128
|
setPublicFilter(newPublicFilter)
|
|
191
|
-
const
|
|
129
|
+
const newInput = buildSearchInput(
|
|
192
130
|
searchQuery,
|
|
193
131
|
newPublicFilter,
|
|
132
|
+
orcidUser?.id,
|
|
133
|
+
hasEdit,
|
|
134
|
+
sortByValue,
|
|
194
135
|
)
|
|
195
|
-
|
|
136
|
+
setSearchInput(newInput)
|
|
196
137
|
refetch({
|
|
197
|
-
query:
|
|
138
|
+
query: newInput,
|
|
198
139
|
cursor: null,
|
|
199
|
-
sortBy: sortBy,
|
|
200
140
|
datasetStatus: undefined,
|
|
201
141
|
})
|
|
202
142
|
},
|
|
203
|
-
[
|
|
204
|
-
setPublicFilter,
|
|
205
|
-
generateElasticsearchQuery,
|
|
206
|
-
refetch,
|
|
207
|
-
searchQuery,
|
|
208
|
-
sortBy,
|
|
209
|
-
hasEdit,
|
|
210
|
-
orcidUser?.id,
|
|
211
|
-
],
|
|
143
|
+
[refetch, searchQuery, sortByValue, hasEdit, orcidUser?.id],
|
|
212
144
|
)
|
|
213
145
|
|
|
214
146
|
const handleSortOrderChange = useCallback(
|
|
215
147
|
(newSortOrder) => {
|
|
216
148
|
setSortOrder(newSortOrder)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
newSortBy = { created: "desc" }
|
|
227
|
-
break
|
|
228
|
-
case "date-oldest":
|
|
229
|
-
newSortBy = { created: "asc" }
|
|
230
|
-
break
|
|
231
|
-
case "date-updated":
|
|
232
|
-
newSortBy = { "metadata.latestSnapshotCreatedAt": "desc" }
|
|
233
|
-
break
|
|
234
|
-
default:
|
|
235
|
-
newSortBy = null
|
|
236
|
-
}
|
|
237
|
-
setSortBy(newSortBy)
|
|
149
|
+
const newSortByValue = SORT_MAP[newSortOrder]
|
|
150
|
+
const newInput = buildSearchInput(
|
|
151
|
+
searchQuery,
|
|
152
|
+
publicFilter,
|
|
153
|
+
orcidUser?.id,
|
|
154
|
+
hasEdit,
|
|
155
|
+
newSortByValue,
|
|
156
|
+
)
|
|
157
|
+
setSearchInput(newInput)
|
|
238
158
|
refetch({
|
|
239
|
-
|
|
159
|
+
query: newInput,
|
|
240
160
|
first: loadAmount,
|
|
241
161
|
cursor: null,
|
|
242
|
-
query: elasticsearchQuery,
|
|
243
162
|
datasetStatus: undefined,
|
|
244
163
|
})
|
|
245
164
|
},
|
|
246
|
-
[
|
|
165
|
+
[refetch, searchQuery, publicFilter, hasEdit, orcidUser?.id],
|
|
247
166
|
)
|
|
248
167
|
|
|
249
168
|
const handleLoadMore = useCallback(() => {
|
|
@@ -256,8 +175,7 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
256
175
|
variables: {
|
|
257
176
|
first: loadAmount,
|
|
258
177
|
cursor: cursor,
|
|
259
|
-
query:
|
|
260
|
-
sortBy: sortBy,
|
|
178
|
+
query: searchInput,
|
|
261
179
|
allDatasets: true,
|
|
262
180
|
datasetStatus: undefined,
|
|
263
181
|
},
|
|
@@ -293,8 +211,7 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
293
211
|
hasNextPage,
|
|
294
212
|
loadMoreLoading,
|
|
295
213
|
cursor,
|
|
296
|
-
|
|
297
|
-
sortBy,
|
|
214
|
+
searchInput,
|
|
298
215
|
hasEdit,
|
|
299
216
|
])
|
|
300
217
|
|
|
@@ -307,23 +224,25 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
|
|
|
307
224
|
}, [data, hasEdit, loadAmount])
|
|
308
225
|
|
|
309
226
|
useEffect(() => {
|
|
310
|
-
const
|
|
227
|
+
const newInput = buildSearchInput(
|
|
311
228
|
searchQuery,
|
|
312
229
|
publicFilter,
|
|
230
|
+
orcidUser?.id,
|
|
231
|
+
hasEdit,
|
|
232
|
+
sortByValue,
|
|
313
233
|
)
|
|
314
|
-
|
|
315
|
-
}, [searchQuery, publicFilter,
|
|
234
|
+
setSearchInput(newInput)
|
|
235
|
+
}, [searchQuery, publicFilter, orcidUser?.id, hasEdit, sortByValue])
|
|
316
236
|
|
|
317
237
|
useEffect(() => {
|
|
318
|
-
if (
|
|
238
|
+
if (searchInput) {
|
|
319
239
|
refetch({
|
|
320
|
-
query:
|
|
240
|
+
query: searchInput,
|
|
321
241
|
cursor: null,
|
|
322
|
-
sortBy: sortBy,
|
|
323
242
|
datasetStatus: undefined,
|
|
324
243
|
})
|
|
325
244
|
}
|
|
326
|
-
}, [
|
|
245
|
+
}, [searchInput, refetch, hasEdit])
|
|
327
246
|
|
|
328
247
|
if (loading) return <Loading />
|
|
329
248
|
if (error) {
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { gql } from "@apollo/client"
|
|
2
|
-
|
|
3
|
-
export const DATASET_COMMENTS = gql`
|
|
4
|
-
fragment DatasetComments on Dataset {
|
|
5
|
-
id
|
|
6
|
-
comments {
|
|
7
|
-
id
|
|
8
|
-
text
|
|
9
|
-
createDate
|
|
10
|
-
user {
|
|
11
|
-
name
|
|
12
|
-
orcid
|
|
13
|
-
}
|
|
14
|
-
parent {
|
|
15
|
-
id
|
|
16
|
-
}
|
|
17
|
-
replies {
|
|
18
|
-
id
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
`
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import PropTypes from "prop-types"
|
|
3
|
-
import { gql } from "@apollo/client"
|
|
4
|
-
import { Mutation } from "@apollo/client/react/components"
|
|
5
|
-
import WarnButton from "../../common/forms/warn-button.jsx"
|
|
6
|
-
import { datasetCacheId } from "./cache-id.js"
|
|
7
|
-
|
|
8
|
-
const FOLLOW_DATASET = gql`
|
|
9
|
-
mutation followDataset($datasetId: ID!) {
|
|
10
|
-
followDataset(datasetId: $datasetId)
|
|
11
|
-
}
|
|
12
|
-
`
|
|
13
|
-
|
|
14
|
-
const USER_FOLLOWING = gql`
|
|
15
|
-
fragment UserFollowing on Dataset {
|
|
16
|
-
id
|
|
17
|
-
following
|
|
18
|
-
}
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
const FollowDataset = ({ datasetId, following }) => (
|
|
22
|
-
<Mutation
|
|
23
|
-
mutation={FOLLOW_DATASET}
|
|
24
|
-
update={(cache, { data: { followDataset } }) => {
|
|
25
|
-
cache.writeFragment({
|
|
26
|
-
id: datasetCacheId(datasetId),
|
|
27
|
-
fragment: USER_FOLLOWING,
|
|
28
|
-
data: {
|
|
29
|
-
__typename: "Dataset",
|
|
30
|
-
id: datasetId,
|
|
31
|
-
following: followDataset,
|
|
32
|
-
},
|
|
33
|
-
})
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
{(followDataset) => (
|
|
37
|
-
<WarnButton
|
|
38
|
-
tooltip="Follow Dataset"
|
|
39
|
-
icon={following ? "fa-tag icon-minus" : "fa-tag icon-plus"}
|
|
40
|
-
warn={false}
|
|
41
|
-
action={(cb) => {
|
|
42
|
-
followDataset({ variables: { datasetId } }).then(() => cb())
|
|
43
|
-
}}
|
|
44
|
-
/>
|
|
45
|
-
)}
|
|
46
|
-
</Mutation>
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
FollowDataset.propTypes = {
|
|
50
|
-
datasetId: PropTypes.string,
|
|
51
|
-
following: PropTypes.bool,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default FollowDataset
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import PropTypes from "prop-types"
|
|
3
|
-
import { gql } from "@apollo/client"
|
|
4
|
-
import { Mutation } from "@apollo/client/react/components"
|
|
5
|
-
import { useNavigate } from "react-router-dom"
|
|
6
|
-
import { datasetCacheId } from "./cache-id.js"
|
|
7
|
-
|
|
8
|
-
const PUBLISH_DATASET = gql`
|
|
9
|
-
mutation publishDataset($datasetId: ID!) {
|
|
10
|
-
publishDataset(datasetId: $datasetId)
|
|
11
|
-
}
|
|
12
|
-
`
|
|
13
|
-
|
|
14
|
-
const DATASET_PUBLISHED = gql`
|
|
15
|
-
fragment DatasetPublished on Dataset {
|
|
16
|
-
id
|
|
17
|
-
public
|
|
18
|
-
}
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
const PublishDataset = ({ datasetId }) => {
|
|
22
|
-
const navigate = useNavigate()
|
|
23
|
-
return (
|
|
24
|
-
<Mutation
|
|
25
|
-
mutation={PUBLISH_DATASET}
|
|
26
|
-
update={(cache) => {
|
|
27
|
-
cache.writeFragment({
|
|
28
|
-
id: datasetCacheId(datasetId),
|
|
29
|
-
fragment: DATASET_PUBLISHED,
|
|
30
|
-
data: {
|
|
31
|
-
__typename: "Dataset",
|
|
32
|
-
id: datasetId,
|
|
33
|
-
public: true,
|
|
34
|
-
},
|
|
35
|
-
})
|
|
36
|
-
}}
|
|
37
|
-
>
|
|
38
|
-
{(publishDataset) => (
|
|
39
|
-
<button
|
|
40
|
-
className="btn-modal-action"
|
|
41
|
-
onClick={() =>
|
|
42
|
-
publishDataset({ variables: { datasetId } }).then(() => {
|
|
43
|
-
navigate(`/datasets/${datasetId}`)
|
|
44
|
-
})}
|
|
45
|
-
>
|
|
46
|
-
Publish
|
|
47
|
-
</button>
|
|
48
|
-
)}
|
|
49
|
-
</Mutation>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
PublishDataset.propTypes = {
|
|
54
|
-
datasetId: PropTypes.string,
|
|
55
|
-
history: PropTypes.object,
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export default PublishDataset
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import PropTypes from "prop-types"
|
|
3
|
-
import { gql } from "@apollo/client"
|
|
4
|
-
import { Mutation } from "@apollo/client/react/components"
|
|
5
|
-
import WarnButton from "../../common/forms/warn-button.jsx"
|
|
6
|
-
import { datasetCacheId } from "./cache-id.js"
|
|
7
|
-
|
|
8
|
-
const STAR_DATASET = gql`
|
|
9
|
-
mutation starDataset($datasetId: ID!) {
|
|
10
|
-
starDataset(datasetId: $datasetId)
|
|
11
|
-
}
|
|
12
|
-
`
|
|
13
|
-
|
|
14
|
-
const USER_STARRED = gql`
|
|
15
|
-
fragment UserStarred on Dataset {
|
|
16
|
-
id
|
|
17
|
-
starred
|
|
18
|
-
}
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
const StarDataset = ({ datasetId, starred }) => (
|
|
22
|
-
<Mutation
|
|
23
|
-
mutation={STAR_DATASET}
|
|
24
|
-
update={(cache, { data: { starDataset } }) => {
|
|
25
|
-
cache.writeFragment({
|
|
26
|
-
id: datasetCacheId(datasetId),
|
|
27
|
-
fragment: USER_STARRED,
|
|
28
|
-
data: {
|
|
29
|
-
__typename: "Dataset",
|
|
30
|
-
id: datasetId,
|
|
31
|
-
starred: starDataset,
|
|
32
|
-
},
|
|
33
|
-
})
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
{(starDataset) => (
|
|
37
|
-
<WarnButton
|
|
38
|
-
tooltip="Save Dataset"
|
|
39
|
-
icon={starred ? "fa-star icon-minus" : "fa-star icon-plus"}
|
|
40
|
-
warn={false}
|
|
41
|
-
action={(cb) => {
|
|
42
|
-
starDataset({ variables: { datasetId } }).then(() => cb())
|
|
43
|
-
}}
|
|
44
|
-
/>
|
|
45
|
-
)}
|
|
46
|
-
</Mutation>
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
StarDataset.propTypes = {
|
|
50
|
-
datasetId: PropTypes.string,
|
|
51
|
-
starred: PropTypes.bool,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default StarDataset
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { gql } from "@apollo/client"
|
|
2
|
-
|
|
3
|
-
export const USER_FRAGMENT = gql`
|
|
4
|
-
fragment userFields on User {
|
|
5
|
-
id
|
|
6
|
-
name
|
|
7
|
-
admin
|
|
8
|
-
blocked
|
|
9
|
-
email
|
|
10
|
-
provider
|
|
11
|
-
lastSeen
|
|
12
|
-
created
|
|
13
|
-
avatar
|
|
14
|
-
github
|
|
15
|
-
institution
|
|
16
|
-
location
|
|
17
|
-
modified
|
|
18
|
-
orcid
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
`
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
// Builds query components using the Elasticsearch Query DSL
|
|
2
|
-
// https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
|
|
3
|
-
|
|
4
|
-
const emptyQuery = () => ({
|
|
5
|
-
bool: {},
|
|
6
|
-
})
|
|
7
|
-
export function BoolQuery() {
|
|
8
|
-
this.query = emptyQuery()
|
|
9
|
-
}
|
|
10
|
-
BoolQuery.prototype.addClause = function (type: string, query: object) {
|
|
11
|
-
if (this.query.bool[type]) {
|
|
12
|
-
this.query.bool[type] = [...this.query.bool[type], query]
|
|
13
|
-
} else {
|
|
14
|
-
this.query.bool[type] = [query]
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
BoolQuery.prototype.get = function () {
|
|
18
|
-
return this.query
|
|
19
|
-
}
|
|
20
|
-
BoolQuery.prototype.toString = function () {
|
|
21
|
-
return JSON.stringify(this.query)
|
|
22
|
-
}
|
|
23
|
-
BoolQuery.prototype.isEmpty = function () {
|
|
24
|
-
return JSON.stringify(this.query) === JSON.stringify(emptyQuery())
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const simpleQueryString = (
|
|
28
|
-
queryString: string,
|
|
29
|
-
fields?: string[],
|
|
30
|
-
fuzzy = true,
|
|
31
|
-
) => ({
|
|
32
|
-
simple_query_string: {
|
|
33
|
-
query: `${queryString}${fuzzy ? "~" : ""}`,
|
|
34
|
-
fields,
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
export const matchQuery = (
|
|
39
|
-
field: string,
|
|
40
|
-
queryString: string,
|
|
41
|
-
fuzziness?: string,
|
|
42
|
-
operator?: string,
|
|
43
|
-
) => ({
|
|
44
|
-
match: {
|
|
45
|
-
[field]: {
|
|
46
|
-
query: queryString,
|
|
47
|
-
fuzziness,
|
|
48
|
-
operator,
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
export const multiMatchQuery = (
|
|
54
|
-
field: string,
|
|
55
|
-
queryStrings: string[],
|
|
56
|
-
fuzziness?: string,
|
|
57
|
-
operator?: string,
|
|
58
|
-
) => {
|
|
59
|
-
return {
|
|
60
|
-
bool: {
|
|
61
|
-
should: queryStrings.map((queryString) =>
|
|
62
|
-
matchQuery(field, queryString, fuzziness, operator)
|
|
63
|
-
),
|
|
64
|
-
minimum_should_match: 1,
|
|
65
|
-
},
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const rangeQuery = (
|
|
70
|
-
field,
|
|
71
|
-
gte?: number | string,
|
|
72
|
-
lte?: number | string,
|
|
73
|
-
relation: string = "INTERSECTS",
|
|
74
|
-
) => ({
|
|
75
|
-
range: {
|
|
76
|
-
[field]: {
|
|
77
|
-
gte,
|
|
78
|
-
lte,
|
|
79
|
-
relation,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
export const rangeListLengthQuery = (field, gte: number, lte: number) => {
|
|
85
|
-
return {
|
|
86
|
-
script: {
|
|
87
|
-
script: {
|
|
88
|
-
lang: "painless",
|
|
89
|
-
source: `
|
|
90
|
-
if (doc[params.field].size() != 0) {
|
|
91
|
-
return ( doc[params.field].size() >= params.gte && doc[params.field].size() <= params.lte )
|
|
92
|
-
} else return false`,
|
|
93
|
-
params: {
|
|
94
|
-
field,
|
|
95
|
-
gte,
|
|
96
|
-
lte,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** SimpleQueryString join multiple terms with and `+`. */
|
|
104
|
-
export const sqsJoinWithAND = (list: string[]) =>
|
|
105
|
-
list.map((str) => `${str}`).join(" + ")
|
|
106
|
-
export const joinWithOR = (list: string[]) =>
|
|
107
|
-
list.map((str) => `${str}`).join(" | ")
|