@openneuro/app 4.37.0-alpha.3 → 4.38.0-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 +2 -2
- package/src/scripts/components/citation/authors-citation-list.ts +23 -0
- package/src/scripts/components/citation/search-results-citation.tsx +33 -0
- package/src/scripts/components/json-tree/RecursiveProperty.tsx +45 -25
- package/src/scripts/components/modality-cube/ModalityHexagon.tsx +5 -1
- package/src/scripts/components/modality-cube/modality-hexagon.scss +74 -23
- package/src/scripts/dataset/__tests__/__snapshots__/snapshot-container.spec.tsx.snap +2 -2
- package/src/scripts/dataset/fragments/__tests__/dataset-citation.spec.jsx +1 -1
- package/src/scripts/dataset/fragments/dataset-citation.jsx +4 -3
- package/src/scripts/errors/errorRoute.tsx +1 -0
- package/src/scripts/errors/orcid/general.jsx +12 -0
- package/src/scripts/queries/user.ts +2 -0
- package/src/scripts/search/components/SearchResultItem.tsx +3 -9
- package/src/scripts/search/search-container.tsx +1 -0
- package/src/scripts/search/use-search-results.tsx +1 -1
- package/src/scripts/types/user-types.ts +5 -0
- package/src/scripts/users/__tests__/dataset-card.spec.tsx +1 -0
- package/src/scripts/users/dataset-card.tsx +10 -0
- package/src/scripts/users/scss/datasetcard.module.scss +174 -167
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/app",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.38.0-alpha.0",
|
|
4
4
|
"description": "React JS web frontend for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "public/client.js",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "96bbcd19e83fab719a0976be7747eeabc5036ff3"
|
|
81
81
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function authorsCitationList(authors: string[], limit?: number): string {
|
|
2
|
+
let formattedAuthors = "NO AUTHORS FOUND"
|
|
3
|
+
if (authors && authors.length > 0) {
|
|
4
|
+
if (!limit || authors.length <= limit) {
|
|
5
|
+
// Pre-Limit
|
|
6
|
+
// Join with commas, with "and" before the last author
|
|
7
|
+
if (authors.length === 1) {
|
|
8
|
+
formattedAuthors = authors[0]
|
|
9
|
+
} else if (authors.length === 2) {
|
|
10
|
+
formattedAuthors = `${authors[0]} and ${authors[1]}`
|
|
11
|
+
} else {
|
|
12
|
+
const lastAuthor = authors[authors.length - 1]
|
|
13
|
+
const remainingAuthors = authors.slice(0, authors.length - 1)
|
|
14
|
+
formattedAuthors = `${remainingAuthors.join(", ")}, and ${lastAuthor}`
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
// Limit to `limit` authors and add "et al."
|
|
18
|
+
const limitedAuthors = authors.slice(0, limit)
|
|
19
|
+
formattedAuthors = `${limitedAuthors.join(", ")}, et al.`
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return formattedAuthors
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { parseISO } from "date-fns"
|
|
3
|
+
import getYear from "date-fns/getYear"
|
|
4
|
+
import type { Dataset } from "../../types/user-types"
|
|
5
|
+
import { authorsCitationList } from "./authors-citation-list"
|
|
6
|
+
|
|
7
|
+
interface SearchResultsCitationProps {
|
|
8
|
+
dataset: Dataset
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const SearchResultsCitation: React.FC<SearchResultsCitationProps> = ({
|
|
12
|
+
dataset,
|
|
13
|
+
}) => {
|
|
14
|
+
const rawAuthors = dataset.latestSnapshot?.description?.Authors
|
|
15
|
+
const year = dataset.created ? getYear(parseISO(dataset.created)) : "N/A"
|
|
16
|
+
const datasetName = dataset.latestSnapshot?.description?.Name ||
|
|
17
|
+
"NO DATASET NAME FOUND"
|
|
18
|
+
const datasetDOI = dataset.latestSnapshot?.description?.DatasetDOI
|
|
19
|
+
|
|
20
|
+
const datasetCite = `${
|
|
21
|
+
authorsCitationList(rawAuthors, 4)
|
|
22
|
+
} (${year}). ${datasetName}. OpenNeuro. [Dataset] doi: ${
|
|
23
|
+
datasetDOI ? `${datasetDOI}` : "N/A"
|
|
24
|
+
}`
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<cite>
|
|
28
|
+
{datasetCite}
|
|
29
|
+
</cite>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default SearchResultsCitation
|
|
@@ -9,53 +9,73 @@ interface IterableObject {
|
|
|
9
9
|
[s: number]: number | string | boolean | IterableObject
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
interface
|
|
13
|
-
property: number | string | boolean | IterableObject
|
|
12
|
+
interface RecursivePropertyProps {
|
|
13
|
+
property: number | string | boolean | IterableObject | null
|
|
14
14
|
propertyName: string
|
|
15
15
|
emptyPropertyLabel?: string
|
|
16
16
|
rootProperty?: boolean
|
|
17
17
|
propertyNameProcessor?: (name: string) => string
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const RecursiveProperty
|
|
20
|
+
export const RecursiveProperty = ({
|
|
21
|
+
property,
|
|
22
|
+
propertyName,
|
|
23
|
+
emptyPropertyLabel,
|
|
24
|
+
rootProperty,
|
|
25
|
+
propertyNameProcessor,
|
|
26
|
+
}: RecursivePropertyProps) => {
|
|
27
|
+
// Determine if the property is "falsy - empty" but should be visible
|
|
28
|
+
const isEmptyValue = property === null ||
|
|
29
|
+
property === 0 ||
|
|
30
|
+
property === 0.0 ||
|
|
31
|
+
property === false ||
|
|
32
|
+
property === ""
|
|
33
|
+
|
|
21
34
|
return (
|
|
22
35
|
<div className="json-container">
|
|
23
|
-
{
|
|
36
|
+
{property !== undefined && (property || isEmptyValue)
|
|
24
37
|
? (
|
|
25
|
-
typeof
|
|
26
|
-
typeof
|
|
27
|
-
typeof
|
|
38
|
+
typeof property === "number" ||
|
|
39
|
+
typeof property === "string" ||
|
|
40
|
+
typeof property === "boolean"
|
|
28
41
|
? (
|
|
29
42
|
<>
|
|
30
43
|
<span className="prop-name">
|
|
31
|
-
{
|
|
44
|
+
{propertyNameProcessor!(propertyName)}:{" "}
|
|
32
45
|
</span>
|
|
33
|
-
{
|
|
46
|
+
{property === null ? "null" : property.toString()}
|
|
34
47
|
</>
|
|
35
48
|
)
|
|
36
49
|
: (
|
|
37
50
|
<ExpandableProperty
|
|
38
|
-
title={
|
|
39
|
-
expanded={!!
|
|
51
|
+
title={propertyNameProcessor!(propertyName)}
|
|
52
|
+
expanded={!!rootProperty}
|
|
40
53
|
>
|
|
41
|
-
{Object.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
{Object.getOwnPropertyNames(property).length > 0
|
|
55
|
+
? (
|
|
56
|
+
Object.values(property).map(
|
|
57
|
+
(propValue, index) => (
|
|
58
|
+
<RecursiveProperty
|
|
59
|
+
key={index}
|
|
60
|
+
property={propValue as
|
|
61
|
+
| number
|
|
62
|
+
| string
|
|
63
|
+
| boolean
|
|
64
|
+
| IterableObject}
|
|
65
|
+
propertyName={Object.getOwnPropertyNames(
|
|
66
|
+
property,
|
|
67
|
+
)[index]}
|
|
68
|
+
propertyNameProcessor={propertyNameProcessor}
|
|
69
|
+
/>
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
: <span className="empty-object-label">No properties</span>}
|
|
54
74
|
</ExpandableProperty>
|
|
55
75
|
)
|
|
56
76
|
)
|
|
57
77
|
: (
|
|
58
|
-
|
|
78
|
+
property === undefined ? emptyPropertyLabel : null
|
|
59
79
|
)}
|
|
60
80
|
</div>
|
|
61
81
|
)
|
|
@@ -4,6 +4,7 @@ import { modalityShortMapping } from "../../components/formatting/modality-label
|
|
|
4
4
|
import "./modality-hexagon.scss"
|
|
5
5
|
interface ModalityHexagonProps {
|
|
6
6
|
primaryModality: string | null | undefined
|
|
7
|
+
size?: string
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
//ModalityHexagon component displays a colored hexagon and label
|
|
@@ -11,6 +12,7 @@ interface ModalityHexagonProps {
|
|
|
11
12
|
|
|
12
13
|
export const ModalityHexagon: FC<ModalityHexagonProps> = ({
|
|
13
14
|
primaryModality,
|
|
15
|
+
size,
|
|
14
16
|
}) => {
|
|
15
17
|
const hexagonClass = primaryModality
|
|
16
18
|
? primaryModality.toLowerCase()
|
|
@@ -20,8 +22,10 @@ export const ModalityHexagon: FC<ModalityHexagonProps> = ({
|
|
|
20
22
|
? modalityShortMapping(primaryModality)
|
|
21
23
|
: <i className="fa fa-circle-o-notch fa-spin"></i>
|
|
22
24
|
|
|
25
|
+
const effectiveSizeClass = size || ""
|
|
26
|
+
|
|
23
27
|
return (
|
|
24
|
-
<div className=
|
|
28
|
+
<div className={`hexagon-wrapper ${effectiveSizeClass}`}>
|
|
25
29
|
<div className={`hexagon ${hexagonClass}`}></div>
|
|
26
30
|
<div className="label">{labelText}</div>
|
|
27
31
|
</div>
|
|
@@ -49,45 +49,96 @@
|
|
|
49
49
|
transform: rotateZ(-60deg);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
&.mri {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
&.
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
&.mri {
|
|
53
|
+
background-color: $mri-theme;
|
|
54
|
+
}
|
|
55
|
+
&.eeg {
|
|
56
|
+
background-color: $on-light-green;
|
|
57
|
+
} // EEG uses on-light-green
|
|
58
|
+
&.pet {
|
|
59
|
+
background-color: $pet-theme;
|
|
60
|
+
}
|
|
61
|
+
&.ieeg {
|
|
62
|
+
background-color: $ieeg-theme;
|
|
63
|
+
}
|
|
64
|
+
&.meg {
|
|
65
|
+
background-color: $meg-theme;
|
|
66
|
+
}
|
|
67
|
+
&.nirs {
|
|
68
|
+
background-color: $nirs-theme;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
&.small {
|
|
72
|
+
margin-left: 10px;
|
|
73
|
+
width: 28px;
|
|
74
|
+
height: 28px;
|
|
75
|
+
div.label {
|
|
76
|
+
font-size: 10px;
|
|
77
|
+
font-weight: normal;
|
|
78
|
+
}
|
|
58
79
|
}
|
|
59
80
|
}
|
|
60
81
|
|
|
82
|
+
|
|
83
|
+
|
|
61
84
|
a {
|
|
62
85
|
.hexagon-wrapper {
|
|
63
|
-
margin: 20px auto;
|
|
86
|
+
margin: 20px auto;
|
|
64
87
|
|
|
65
88
|
div.label {
|
|
66
|
-
color: unset;
|
|
89
|
+
color: unset;
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
.hexagon {
|
|
70
|
-
transition: color 0.3s;
|
|
71
|
-
background-color: #fff;
|
|
93
|
+
transition: color 0.3s;
|
|
94
|
+
background-color: #fff;
|
|
72
95
|
|
|
73
96
|
// Modality specific colors (when inside 'a')
|
|
74
|
-
&.mri {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
&.
|
|
79
|
-
|
|
97
|
+
&.mri {
|
|
98
|
+
background-color: #fff;
|
|
99
|
+
color: $mri-theme;
|
|
100
|
+
}
|
|
101
|
+
&.eeg {
|
|
102
|
+
background-color: #fff;
|
|
103
|
+
color: $eeg-theme;
|
|
104
|
+
}
|
|
105
|
+
&.pet {
|
|
106
|
+
background-color: #fff;
|
|
107
|
+
color: $pet-theme;
|
|
108
|
+
}
|
|
109
|
+
&.ieeg {
|
|
110
|
+
background-color: #fff;
|
|
111
|
+
color: $ieeg-theme;
|
|
112
|
+
}
|
|
113
|
+
&.meg {
|
|
114
|
+
background-color: #fff;
|
|
115
|
+
color: $meg-theme;
|
|
116
|
+
}
|
|
117
|
+
&.nirs {
|
|
118
|
+
background-color: #fff;
|
|
119
|
+
color: $nirs-theme;
|
|
120
|
+
}
|
|
80
121
|
}
|
|
81
122
|
|
|
82
123
|
&:hover {
|
|
83
124
|
.hexagon {
|
|
84
|
-
color: lighten($on-dark-aqua, 15%);
|
|
85
|
-
&.mri {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
&.
|
|
89
|
-
|
|
125
|
+
color: lighten($on-dark-aqua, 15%);
|
|
126
|
+
&.mri {
|
|
127
|
+
color: lighten($mri-theme, 10%);
|
|
128
|
+
}
|
|
129
|
+
&.eeg {
|
|
130
|
+
color: lighten($eeg-theme, 10%);
|
|
131
|
+
}
|
|
132
|
+
&.pet {
|
|
133
|
+
color: lighten($pet-theme, 10%);
|
|
134
|
+
}
|
|
135
|
+
&.ieeg {
|
|
136
|
+
color: lighten($ieeg-theme, 10%);
|
|
137
|
+
}
|
|
138
|
+
&.meg {
|
|
139
|
+
color: lighten($meg-theme, 10%);
|
|
140
|
+
}
|
|
90
141
|
}
|
|
91
142
|
}
|
|
92
143
|
}
|
|
93
|
-
}
|
|
144
|
+
}
|
|
@@ -49,7 +49,7 @@ exports[`SnapshotContainer component > renders successfully 1`] = `
|
|
|
49
49
|
href="/search/modality/MRI"
|
|
50
50
|
>
|
|
51
51
|
<div
|
|
52
|
-
class="hexagon-wrapper"
|
|
52
|
+
class="hexagon-wrapper "
|
|
53
53
|
>
|
|
54
54
|
<div
|
|
55
55
|
class="hexagon mri"
|
|
@@ -1042,7 +1042,7 @@ OCI-1131441 (R. Poldrack, PI) in any publications.
|
|
|
1042
1042
|
<h5
|
|
1043
1043
|
class="cite-content-block"
|
|
1044
1044
|
>
|
|
1045
|
-
J. Doe
|
|
1045
|
+
J. Doe, J. Doe, and J. Doe (2021). DS003-downsampled (only T1). OpenNeuro. [Dataset] doi: null
|
|
1046
1046
|
</h5>
|
|
1047
1047
|
</div>
|
|
1048
1048
|
<h5>
|
|
@@ -18,7 +18,7 @@ describe("formatCitation", () => {
|
|
|
18
18
|
})
|
|
19
19
|
it('should work with "BibTeX" input', () => {
|
|
20
20
|
expect(formatCitation(snapshot, "BibTeX")).toEqual(`@dataset{ds999999:1.0.2,
|
|
21
|
-
author = {Jane Doe
|
|
21
|
+
author = {Jane Doe AND Doe, John},
|
|
22
22
|
title = {"A Test Dataset"},
|
|
23
23
|
year = {2020},
|
|
24
24
|
doi = {doinumbersgohere},
|
|
@@ -5,17 +5,18 @@ import parseISO from "date-fns/parseISO"
|
|
|
5
5
|
import { CopyToClipboard } from "react-copy-to-clipboard"
|
|
6
6
|
import { Button } from "../../components/button/Button"
|
|
7
7
|
import { Tooltip } from "../../components/tooltip/Tooltip"
|
|
8
|
+
import { authorsCitationList } from "../../components/citation/authors-citation-list"
|
|
8
9
|
|
|
9
10
|
export const formatCitation = (snapshot, style) => {
|
|
10
11
|
const year = getYear(parseISO(snapshot.created))
|
|
11
12
|
const authors = snapshot.description.Authors
|
|
12
|
-
? snapshot.description.Authors
|
|
13
|
-
: "
|
|
13
|
+
? authorsCitationList(snapshot.description.Authors)
|
|
14
|
+
: ""
|
|
14
15
|
if (style === "Text") {
|
|
15
16
|
return `${authors} (${year}). ${snapshot.description.Name}. OpenNeuro. [Dataset] doi: ${snapshot.description.DatasetDOI}`
|
|
16
17
|
} else if (style === "BibTeX") {
|
|
17
18
|
return `@dataset{${snapshot.id},
|
|
18
|
-
author = {${
|
|
19
|
+
author = {${snapshot.description.Authors.join(" AND ")}},
|
|
19
20
|
title = {"${snapshot.description.Name}"},
|
|
20
21
|
year = {${year}},
|
|
21
22
|
doi = {${snapshot.description.DatasetDOI}},
|
|
@@ -15,6 +15,7 @@ function ErrorRoute() {
|
|
|
15
15
|
<Routes>
|
|
16
16
|
<Route path="github" element={<FourOThreePage />} />
|
|
17
17
|
<Route path="orcid" element={<OrcidGeneral />} />
|
|
18
|
+
<Route path="orcid/unknown" element={<OrcidGeneral />} />
|
|
18
19
|
<Route path="email-warning" element={<OrcidEmailWarning />} />
|
|
19
20
|
<Route path="*" element={<FourOFourPage />} />
|
|
20
21
|
</Routes>
|
|
@@ -3,6 +3,18 @@ import React from "react"
|
|
|
3
3
|
const OrcidError = () => (
|
|
4
4
|
<div className="panel-heading">
|
|
5
5
|
<h2>There was an issue authenticating with your ORCID account.</h2>
|
|
6
|
+
<p>
|
|
7
|
+
This may be a temporary issue, please try again later. Ensure that your
|
|
8
|
+
ORCID profile has one email address available to OpenNeuro following{" "}
|
|
9
|
+
<a href="https://docs.openneuro.org/orcid.html#enabling-trusted-access-to-emails">
|
|
10
|
+
our documentation
|
|
11
|
+
</a>{" "}
|
|
12
|
+
and try again.
|
|
13
|
+
</p>
|
|
14
|
+
<p>
|
|
15
|
+
If this issue persists, please contact support and include the ORCID
|
|
16
|
+
account you're attempting to login with.
|
|
17
|
+
</p>
|
|
6
18
|
</div>
|
|
7
19
|
)
|
|
8
20
|
|
|
@@ -117,6 +117,7 @@ export const ADVANCED_SEARCH_DATASETS_QUERY = gql`
|
|
|
117
117
|
TracerName
|
|
118
118
|
TracerRadionuclide
|
|
119
119
|
}
|
|
120
|
+
primaryModality
|
|
120
121
|
}
|
|
121
122
|
issues {
|
|
122
123
|
severity
|
|
@@ -128,6 +129,7 @@ export const ADVANCED_SEARCH_DATASETS_QUERY = gql`
|
|
|
128
129
|
description {
|
|
129
130
|
Name
|
|
130
131
|
Authors
|
|
132
|
+
DatasetDOI
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
analytics {
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import React from "react"
|
|
2
|
-
import getYear from "date-fns/getYear"
|
|
3
|
-
import parseISO from "date-fns/parseISO"
|
|
4
2
|
import { Link } from "react-router-dom"
|
|
5
3
|
import { Tooltip } from "../../components/tooltip/Tooltip"
|
|
6
4
|
import { Icon } from "../../components/icon/Icon"
|
|
@@ -11,6 +9,7 @@ import "../scss/search-result.scss"
|
|
|
11
9
|
import activityPulseIcon from "../../../assets/activity-icon.png"
|
|
12
10
|
import { hasEditPermissions } from "../../authentication/profile"
|
|
13
11
|
import { ModalityHexagon } from "../../components/modality-cube/ModalityHexagon"
|
|
12
|
+
import { SearchResultsCitation } from "../../components/citation/search-results-citation"
|
|
14
13
|
|
|
15
14
|
export const formatDate = (dateObject) =>
|
|
16
15
|
new Date(dateObject).toISOString().split("T")[0]
|
|
@@ -19,6 +18,7 @@ export interface SearchResultItemProps {
|
|
|
19
18
|
node: {
|
|
20
19
|
id: string
|
|
21
20
|
created: string
|
|
21
|
+
name: string
|
|
22
22
|
uploader: {
|
|
23
23
|
id: string
|
|
24
24
|
name: string
|
|
@@ -243,12 +243,6 @@ export const SearchResultItem = ({
|
|
|
243
243
|
</div>
|
|
244
244
|
)
|
|
245
245
|
|
|
246
|
-
const year = getYear(parseISO(node.created))
|
|
247
|
-
const authors = node.latestSnapshot.description?.Authors
|
|
248
|
-
? node.latestSnapshot.description.Authors.join(" and ")
|
|
249
|
-
: "NO AUTHORS FOUND"
|
|
250
|
-
const datasetCite =
|
|
251
|
-
`${authors} (${year}). ${node.latestSnapshot.description.Name}. OpenNeuro. [Dataset] doi: ${node.latestSnapshot.description.DatasetDOI}`
|
|
252
246
|
const trimlength = 450
|
|
253
247
|
|
|
254
248
|
return (
|
|
@@ -270,7 +264,7 @@ export const SearchResultItem = ({
|
|
|
270
264
|
: node.latestSnapshot.readme)
|
|
271
265
|
: ""}
|
|
272
266
|
</p>
|
|
273
|
-
<
|
|
267
|
+
<SearchResultsCitation dataset={node} />
|
|
274
268
|
</div>
|
|
275
269
|
</div>
|
|
276
270
|
|
|
@@ -404,7 +404,7 @@ export const useSearchResults = () => {
|
|
|
404
404
|
// fetchPolicy is workaround for stuck loading bug (https://github.com/apollographql/react-apollo/issues/3270#issuecomment-579614837)
|
|
405
405
|
// TODO: find better solution
|
|
406
406
|
fetchPolicy: "cache-and-network",
|
|
407
|
-
nextFetchPolicy: "cache-
|
|
407
|
+
nextFetchPolicy: "cache-and-network",
|
|
408
408
|
notifyOnNetworkStatusChange: true,
|
|
409
409
|
})
|
|
410
410
|
}
|
|
@@ -5,6 +5,8 @@ import { Tooltip } from "../components/tooltip/Tooltip"
|
|
|
5
5
|
import { Icon } from "../components/icon/Icon"
|
|
6
6
|
import styles from "./scss/datasetcard.module.scss"
|
|
7
7
|
import type { DatasetCardProps } from "../types/user-types"
|
|
8
|
+
import { ModalityHexagon } from "../components/modality-cube/ModalityHexagon"
|
|
9
|
+
import { SearchResultsCitation } from "../components/citation/search-results-citation"
|
|
8
10
|
|
|
9
11
|
export const DatasetCard: React.FC<DatasetCardProps> = (
|
|
10
12
|
{ dataset, hasEdit },
|
|
@@ -87,6 +89,7 @@ export const DatasetCard: React.FC<DatasetCardProps> = (
|
|
|
87
89
|
datasetSize = `${sizeInBytes} bytes`
|
|
88
90
|
}
|
|
89
91
|
}
|
|
92
|
+
|
|
90
93
|
return (
|
|
91
94
|
<div
|
|
92
95
|
className={styles.userDsCard}
|
|
@@ -98,6 +101,9 @@ export const DatasetCard: React.FC<DatasetCardProps> = (
|
|
|
98
101
|
{dataset.name ? dataset.name : dataset.id}
|
|
99
102
|
</a>
|
|
100
103
|
</h4>
|
|
104
|
+
<div className={styles.userDsBody}>
|
|
105
|
+
<SearchResultsCitation dataset={dataset} />
|
|
106
|
+
</div>
|
|
101
107
|
<div className={styles.userDsFooter}>
|
|
102
108
|
<div className={styles.userMetawrap}>
|
|
103
109
|
<span>
|
|
@@ -113,6 +119,10 @@ export const DatasetCard: React.FC<DatasetCardProps> = (
|
|
|
113
119
|
<div className={styles.userIconwrap}>
|
|
114
120
|
{activityIcon}
|
|
115
121
|
{publicIcon && <div className="owner-icon-wrap">{publicIcon}</div>}
|
|
122
|
+
<ModalityHexagon
|
|
123
|
+
size={"small"}
|
|
124
|
+
primaryModality={dataset.latestSnapshot.summary?.primaryModality}
|
|
125
|
+
/>
|
|
116
126
|
</div>
|
|
117
127
|
</div>
|
|
118
128
|
</div>
|
|
@@ -1,194 +1,203 @@
|
|
|
1
1
|
.userDsWrap {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.userDsCard {
|
|
8
|
+
background: #fff;
|
|
9
|
+
border: 1px solid #ddd;
|
|
10
|
+
width: calc(50% - 10px);
|
|
11
|
+
padding: 10px;
|
|
12
|
+
margin-bottom: 20px;
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: space-between;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
|
|
17
|
+
h4 {
|
|
18
|
+
margin: 0 0 15px;
|
|
19
|
+
font-size: 19px;
|
|
5
20
|
}
|
|
6
|
-
|
|
7
|
-
.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
}
|
|
22
|
+
.userDsBody {
|
|
23
|
+
margin-bottom: 15px;
|
|
24
|
+
cite {
|
|
25
|
+
color: var(--text-citation);
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
.userDsFooter {
|
|
13
30
|
display: flex;
|
|
14
31
|
justify-content: space-between;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
margin: 0 0 30px;
|
|
19
|
-
font-size: 19px;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.userDsFooter {
|
|
32
|
+
|
|
33
|
+
.userMetawrap {
|
|
34
|
+
width: 90%;
|
|
23
35
|
display: flex;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
|
|
38
|
+
span {
|
|
39
|
+
color: #777;
|
|
40
|
+
|
|
41
|
+
b {
|
|
42
|
+
color: #000;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&:first-child {
|
|
46
|
+
font-size: 13px;
|
|
47
|
+
margin-bottom: 10px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&:last-child {
|
|
51
|
+
text-transform: uppercase;
|
|
52
|
+
font-weight: bold;
|
|
53
|
+
|
|
34
54
|
b {
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
&:first-child {
|
|
39
|
-
font-size: 13px;
|
|
40
|
-
margin-bottom: 10px;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
&:last-child {
|
|
44
|
-
text-transform: uppercase;
|
|
45
|
-
font-weight: bold;
|
|
46
|
-
|
|
47
|
-
b {
|
|
48
|
-
text-transform: none;
|
|
49
|
-
}
|
|
55
|
+
text-transform: none;
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.userIconwrap {
|
|
62
|
+
display: flex;
|
|
63
|
+
justify-content: flex-end;
|
|
64
|
+
align-items: center;
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
|
|
69
|
+
.resultsSummary {
|
|
70
|
+
width: 100%;
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
margin: 10px 0 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.userDSfilters {
|
|
76
|
+
display: flex;
|
|
77
|
+
justify-content: flex-end;
|
|
78
|
+
flex-wrap: wrap;
|
|
79
|
+
margin: 20px 0;
|
|
80
|
+
padding-bottom: 20px;
|
|
81
|
+
align-items: center;
|
|
82
|
+
z-index: 10000;
|
|
83
|
+
position: relative;
|
|
84
|
+
border-bottom: 2px solid #eee;
|
|
85
|
+
|
|
86
|
+
.searchLink {
|
|
87
|
+
margin-right: auto;
|
|
66
88
|
}
|
|
67
|
-
|
|
68
|
-
.
|
|
89
|
+
.filterDiv,
|
|
90
|
+
.sortDiv {
|
|
91
|
+
cursor: pointer;
|
|
69
92
|
display: flex;
|
|
70
|
-
justify-content: flex-end;
|
|
71
|
-
flex-wrap: wrap;
|
|
72
|
-
margin: 20px 0;
|
|
73
|
-
padding-bottom:20px;
|
|
74
93
|
align-items: center;
|
|
75
|
-
z-index: 10000;
|
|
76
94
|
position: relative;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.searchLink{
|
|
80
|
-
margin-right: auto;
|
|
95
|
+
margin-bottom: 5px;
|
|
81
96
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
|
|
98
|
+
/* Caret icon */
|
|
99
|
+
.filterDiv span::after,
|
|
100
|
+
.sortDiv span::after {
|
|
101
|
+
content: '';
|
|
102
|
+
width: 0;
|
|
103
|
+
height: 0;
|
|
104
|
+
border-left: 5px solid transparent;
|
|
105
|
+
border-right: 5px solid transparent;
|
|
106
|
+
border-top: 5px solid #333;
|
|
107
|
+
margin-left: 10px;
|
|
108
|
+
transition: transform 0.3s ease;
|
|
109
|
+
display: inline-block;
|
|
110
|
+
margin-bottom: 3px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.filterDiv.open span::after,
|
|
114
|
+
.sortDiv.open span::after {
|
|
115
|
+
transform: rotate(180deg); /* Rotate the caret when open */
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.filterDropdown,
|
|
119
|
+
.sortDropdown {
|
|
120
|
+
position: relative;
|
|
121
|
+
|
|
122
|
+
ul {
|
|
123
|
+
position: absolute;
|
|
124
|
+
list-style-type: none;
|
|
85
125
|
display: flex;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.filterDiv.open span::after,
|
|
107
|
-
.sortDiv.open span::after {
|
|
108
|
-
transform: rotate(180deg); /* Rotate the caret when open */
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.filterDropdown,
|
|
112
|
-
.sortDropdown {
|
|
113
|
-
position: relative;
|
|
114
|
-
|
|
115
|
-
ul {
|
|
116
|
-
position: absolute;
|
|
117
|
-
list-style-type: none;
|
|
118
|
-
display: flex;
|
|
119
|
-
flex-direction: column;
|
|
120
|
-
margin: 0;
|
|
121
|
-
padding: 20px;
|
|
122
|
-
background-color: white;
|
|
123
|
-
border: 1px solid #ddd;
|
|
124
|
-
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
125
|
-
right: 0;
|
|
126
|
-
top: 20px;
|
|
127
|
-
min-width: 200px;
|
|
128
|
-
li {
|
|
129
|
-
padding: 8px;
|
|
130
|
-
cursor: pointer;
|
|
131
|
-
|
|
132
|
-
&:hover {
|
|
133
|
-
background-color: #f4f4f4;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
&.active {
|
|
137
|
-
font-weight: bold;
|
|
138
|
-
color: var(--on-dark-aqua);
|
|
139
|
-
}
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
margin: 0;
|
|
128
|
+
padding: 20px;
|
|
129
|
+
background-color: white;
|
|
130
|
+
border: 1px solid #ddd;
|
|
131
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
132
|
+
right: 0;
|
|
133
|
+
top: 20px;
|
|
134
|
+
min-width: 200px;
|
|
135
|
+
li {
|
|
136
|
+
padding: 8px;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
|
|
139
|
+
&:hover {
|
|
140
|
+
background-color: #f4f4f4;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&.active {
|
|
144
|
+
font-weight: bold;
|
|
145
|
+
color: var(--on-dark-aqua);
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
|
-
|
|
144
|
-
.filterDropdown {
|
|
145
|
-
ul {min-width: 120px;}
|
|
146
|
-
}
|
|
147
|
-
.sortDiv {
|
|
148
|
-
margin-left: 20px;
|
|
149
|
-
}
|
|
150
149
|
}
|
|
151
150
|
|
|
152
|
-
.
|
|
153
|
-
|
|
151
|
+
.filterDropdown {
|
|
152
|
+
ul {
|
|
153
|
+
min-width: 120px;
|
|
154
|
+
}
|
|
154
155
|
}
|
|
155
|
-
.
|
|
156
|
+
.sortDiv {
|
|
157
|
+
margin-left: 20px;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.userDatasetsWrapper {
|
|
162
|
+
margin-bottom: 50px;
|
|
163
|
+
}
|
|
164
|
+
.searchInputContainer {
|
|
165
|
+
position: relative;
|
|
166
|
+
display: flex;
|
|
167
|
+
|
|
168
|
+
.searchInputWrap {
|
|
156
169
|
position: relative;
|
|
157
|
-
display: flex;
|
|
158
|
-
|
|
159
|
-
.searchInputWrap{
|
|
160
|
-
position: relative;
|
|
161
170
|
width: 100%;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
.clearSearchButton {
|
|
171
|
-
position: absolute;
|
|
172
|
-
top: 50%;
|
|
173
|
-
right: 5px; /* Adjust position as needed */
|
|
174
|
-
transform: translateY(-50%);
|
|
175
|
-
background: none;
|
|
176
|
-
border: none;
|
|
177
|
-
cursor: pointer;
|
|
178
|
-
font-size: 0.8em;
|
|
179
|
-
color: #888;
|
|
180
|
-
padding: 0;
|
|
181
|
-
width: 20px;
|
|
182
|
-
height: 20px;
|
|
183
|
-
display: flex;
|
|
184
|
-
align-items: center;
|
|
185
|
-
justify-content: center;
|
|
186
|
-
|
|
187
|
-
&:hover {
|
|
188
|
-
color: #333;
|
|
171
|
+
.searchInput {
|
|
172
|
+
flex-grow: 1;
|
|
173
|
+
padding-right: 30px;
|
|
174
|
+
margin-right: auto;
|
|
175
|
+
width: 100%;
|
|
189
176
|
}
|
|
190
|
-
|
|
191
|
-
.
|
|
177
|
+
|
|
178
|
+
.clearSearchButton {
|
|
179
|
+
position: absolute;
|
|
180
|
+
top: 50%;
|
|
181
|
+
right: 5px; /* Adjust position as needed */
|
|
182
|
+
transform: translateY(-50%);
|
|
183
|
+
background: none;
|
|
184
|
+
border: none;
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
font-size: 0.8em;
|
|
187
|
+
color: #888;
|
|
188
|
+
padding: 0;
|
|
189
|
+
width: 20px;
|
|
190
|
+
height: 20px;
|
|
191
|
+
display: flex;
|
|
192
|
+
align-items: center;
|
|
193
|
+
justify-content: center;
|
|
194
|
+
|
|
195
|
+
&:hover {
|
|
196
|
+
color: #333;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
.searchSubmitButton {
|
|
192
201
|
background-color: var(--current-theme-secondary);
|
|
193
202
|
color: #fff;
|
|
194
203
|
border-radius: var(--border-radius-default);
|
|
@@ -201,6 +210,4 @@
|
|
|
201
210
|
background-color: var(--current-theme-primary);
|
|
202
211
|
}
|
|
203
212
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
213
|
+
}
|