@openneuro/app 4.19.2 → 4.20.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.
Files changed (71) hide show
  1. package/package.json +11 -22
  2. package/src/client.jsx +0 -1
  3. package/src/scripts/authentication/__tests__/profile.spec.js +1 -1
  4. package/src/scripts/authentication/admin-user.jsx +1 -1
  5. package/src/scripts/authentication/loginCheck.js +1 -1
  6. package/src/scripts/authentication/{profile.js → profile.ts} +12 -2
  7. package/src/scripts/authentication/regular-user.tsx +1 -1
  8. package/src/scripts/authentication/withProfile.jsx +1 -1
  9. package/src/scripts/common/forms/__tests__/__snapshots__/warn-button.spec.jsx.snap +1 -1
  10. package/src/scripts/components/__tests__/__snapshots__/data-table.spec.tsx.snap +84 -0
  11. package/src/scripts/components/__tests__/data-table.spec.tsx +15 -0
  12. package/src/scripts/components/data-table.tsx +125 -0
  13. package/src/scripts/datalad/subscriptions/__tests__/__snapshots__/files-subscription.spec.jsx.snap +1 -1
  14. package/src/scripts/dataset/__tests__/__snapshots__/snapshot-container.spec.tsx.snap +3 -3
  15. package/src/scripts/dataset/comments/__tests__/__snapshots__/comment.spec.jsx.snap +1 -1
  16. package/src/scripts/dataset/comments/__tests__/__snapshots__/comments.spec.jsx.snap +1 -1
  17. package/src/scripts/dataset/common/follow-toggles.tsx +2 -0
  18. package/src/scripts/dataset/dataset-query.jsx +2 -109
  19. package/src/scripts/dataset/download/__tests__/__snapshots__/download-command-line.spec.jsx.snap +1 -1
  20. package/src/scripts/dataset/download/__tests__/__snapshots__/download-link.spec.jsx.snap +1 -1
  21. package/src/scripts/dataset/download/__tests__/__snapshots__/shell-example.spec.jsx.snap +1 -1
  22. package/src/scripts/dataset/draft-container.tsx +2 -2
  23. package/src/scripts/dataset/files/__tests__/__snapshots__/file-tree.spec.jsx.snap +1 -1
  24. package/src/scripts/dataset/files/__tests__/__snapshots__/file.spec.jsx.snap +1 -1
  25. package/src/scripts/dataset/files/file.tsx +3 -2
  26. package/src/scripts/dataset/files/viewers/__tests__/__snapshots__/file-viewer-json.spec.jsx.snap +1 -1
  27. package/src/scripts/dataset/files/viewers/file-viewer-csv.jsx +1 -1
  28. package/src/scripts/dataset/files/viewers/file-viewer-table.tsx +18 -0
  29. package/src/scripts/dataset/files/viewers/file-viewer-tsv.jsx +1 -1
  30. package/src/scripts/dataset/fragments/__tests__/__snapshots__/cancel-button.spec.tsx.snap +1 -1
  31. package/src/scripts/dataset/fragments/__tests__/__snapshots__/edit-button.spec.tsx.snap +1 -1
  32. package/src/scripts/dataset/fragments/__tests__/__snapshots__/edit-list.spec.jsx.snap +1 -1
  33. package/src/scripts/dataset/fragments/__tests__/__snapshots__/save-button.spec.tsx.snap +1 -1
  34. package/src/scripts/dataset/fragments/__tests__/__snapshots__/select-input.spec.tsx.snap +1 -1
  35. package/src/scripts/dataset/fragments/comments-fragments.js +2 -1
  36. package/src/scripts/dataset/fragments/text-input.tsx +1 -1
  37. package/src/scripts/dataset/mutations/__tests__/__snapshots__/delete.spec.jsx.snap +1 -1
  38. package/src/scripts/dataset/mutations/__tests__/__snapshots__/deprecate-snapshot.spec.tsx.snap +1 -1
  39. package/src/scripts/dataset/mutations/__tests__/__snapshots__/deprecate-version.spec.tsx.snap +1 -1
  40. package/src/scripts/dataset/mutations/__tests__/__snapshots__/description.spec.jsx.snap +1 -1
  41. package/src/scripts/dataset/mutations/__tests__/__snapshots__/update-permissions.spec.jsx.snap +1 -1
  42. package/src/scripts/dataset/mutations/comment.jsx +1 -1
  43. package/src/scripts/dataset/mutations/delete-anonymous-reviewer.tsx +4 -1
  44. package/src/scripts/dataset/mutations/snapshot.tsx +10 -2
  45. package/src/scripts/dataset/routes/add-metadata.jsx +1 -1
  46. package/src/scripts/dataset/routes/delete-page.tsx +1 -1
  47. package/src/scripts/dataset/routes/manage-permissions.jsx +1 -2
  48. package/src/scripts/dataset/routes/{snapshot.jsx → snapshot.tsx} +8 -11
  49. package/src/scripts/dataset/routes/styles/dataset-page-border.tsx +2 -0
  50. package/src/scripts/dataset/routes/styles/dataset-page-tab-container.tsx +2 -0
  51. package/src/scripts/dataset/routes/styles/header-row.tsx +2 -0
  52. package/src/scripts/dataset/routes/tab-routes-draft.tsx +1 -1
  53. package/src/scripts/dataset/snapshot-container.tsx +2 -2
  54. package/src/scripts/pages/admin/user-tools.tsx +1 -1
  55. package/src/scripts/pages/faq/faq.tsx +8 -0
  56. package/src/scripts/pages/metadata/dataset-metadata.tsx +86 -0
  57. package/src/scripts/queries/dataset.ts +113 -0
  58. package/src/scripts/routes.tsx +2 -0
  59. package/src/scripts/search/__helpers__/search-render.tsx +1 -0
  60. package/src/scripts/search/initial-search-params.tsx +1 -1
  61. package/src/scripts/search/search-routes.tsx +1 -1
  62. package/src/scripts/search/use-search-results.tsx +1 -1
  63. package/src/scripts/styles/media.tsx +2 -0
  64. package/src/scripts/utils/__tests__/csv.spec.ts +41 -0
  65. package/src/scripts/utils/csv.ts +41 -0
  66. package/src/scripts/utils/schema-validator.js +1 -1
  67. package/src/scripts/dataset/files/viewers/file-viewer-table.jsx +0 -35
  68. package/src/scripts/pages/faq/__tests__/__snapshots__/faq.spec.jsx.snap +0 -302
  69. package/src/scripts/pages/faq/__tests__/faq.spec.jsx +0 -10
  70. package/src/scripts/pages/faq/faq-content.js +0 -121
  71. package/src/scripts/pages/faq/faq.jsx +0 -16
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+ import { DataTable } from '../../../components/data-table'
3
+ import styled from '@emotion/styled'
4
+
5
+ const TableOverlow = styled.div`
6
+ overflow-x: scroll;
7
+ height: 64vh;
8
+ `
9
+
10
+ const FileViewerTable = ({ tableData }): React.ReactElement => {
11
+ return (
12
+ <TableOverlow>
13
+ <DataTable data={tableData}></DataTable>
14
+ </TableOverlow>
15
+ )
16
+ }
17
+
18
+ export default FileViewerTable
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import parseTabular from './parse-tabular.js'
4
- import FileViewerTable from './file-viewer-table.jsx'
4
+ import FileViewerTable from './file-viewer-table'
5
5
 
6
6
  const FileViewerTsv = ({ data }) => {
7
7
  const decoder = new TextDecoder()
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`CancelButton component > renders with default props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`EditButton component > renders with default props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`EditList component > renders with default props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`SaveButton component > renders with default props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`SelectInput > handles boolean display 1`] = `
4
4
  <DocumentFragment>
@@ -8,7 +8,8 @@ export const DATASET_COMMENTS = gql`
8
8
  text
9
9
  createDate
10
10
  user {
11
- email
11
+ name
12
+ orcid
12
13
  }
13
14
  parent {
14
15
  id
@@ -107,7 +107,7 @@ const TextInput = ({
107
107
  required,
108
108
  onChange,
109
109
  }): React.ReactElement => {
110
- if (value === null) {
110
+ if (value === null || value === undefined) {
111
111
  if (nullMessage) value = nullMessage
112
112
  else value = ''
113
113
  } else value = value.toString()
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`DeleteDataset mutation > renders with common props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`DeprecateVersion mutation > renders with typical props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`DeprecateVersion mutation > renders with typical props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`UpdateDescription mutation > renders with common props 1`] = `
4
4
  <DocumentFragment>
@@ -1,4 +1,4 @@
1
- // Vitest Snapshot v1
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`UpdateDatasetPermissions mutation > renders with default props 1`] = `
4
4
  <DocumentFragment>
@@ -70,7 +70,7 @@ export const newCommentsReducer = (
70
70
  }
71
71
 
72
72
  /**
73
- * Modify an exsiting comment and return new state based on arguments
73
+ * Modify an existing comment and return new state based on arguments
74
74
  * @param {Object[]} comments
75
75
  * @param {Object} arguments
76
76
  * @param {string} arguments.commentId
@@ -20,10 +20,13 @@ interface DeleteReviewerLinkProps {
20
20
  export const DeleteReviewerLink: FC<DeleteReviewerLinkProps> = ({
21
21
  datasetId,
22
22
  id,
23
+ }: {
24
+ datasetId: string
25
+ id: string
23
26
  }) => {
24
27
  const [DeleteReviewerLink] = useMutation(DELETE_REVIEWER, {
25
28
  update(cache, { data: { deleteReviewer } }) {
26
- const { reviewers } = cache.readFragment({
29
+ const { reviewers } = cache.readFragment<{ reviewers: any[] }>({
27
30
  id: `Dataset:${datasetId}`,
28
31
  fragment: DATASET_REVIEWERS,
29
32
  })
@@ -4,12 +4,15 @@ import { gql, useMutation } from '@apollo/client'
4
4
  import { useNavigate } from 'react-router-dom'
5
5
  import ErrorBoundary from '../../errors/errorBoundary.jsx'
6
6
  import { Button } from '@openneuro/components/button'
7
+ import { getDatasetPage, getDraftPage } from '../../queries/dataset'
7
8
 
8
9
  const CREATE_SNAPSHOT = gql`
9
10
  mutation createSnapshot($datasetId: ID!, $tag: String!, $changes: [String!]) {
10
11
  createSnapshot(datasetId: $datasetId, tag: $tag, changes: $changes) {
11
12
  id
12
13
  tag
14
+ created
15
+ hexsha
13
16
  }
14
17
  }
15
18
  `
@@ -28,7 +31,9 @@ const CreateSnapshotMutation = ({
28
31
  disabled,
29
32
  }: CreateSnapshotMutationProps) => {
30
33
  const navigate = useNavigate()
31
- const [snapshotDataset, { loading, error }] = useMutation(CREATE_SNAPSHOT)
34
+ const [snapshotDataset, { loading, error }] = useMutation(CREATE_SNAPSHOT, {
35
+ refetchQueries: [getDatasetPage, getDraftPage],
36
+ })
32
37
 
33
38
  if (error) throw error
34
39
 
@@ -42,7 +47,10 @@ const CreateSnapshotMutation = ({
42
47
  onClick={(): void => {
43
48
  void snapshotDataset({
44
49
  variables: { datasetId, tag, changes },
45
- }).then(() => navigate(`/datasets/${datasetId}/versions/${tag}`))
50
+ }).then(data => {
51
+ console.log(data)
52
+ navigate(`/datasets/${datasetId}/versions/${tag}`)
53
+ })
46
54
  }}
47
55
  disabled={disabled}
48
56
  label="Create Version"
@@ -6,7 +6,7 @@ import MetadataForm from '../mutations/metadata-form.jsx'
6
6
  import { DatasetRelations } from '../mutations/dataset-relations'
7
7
  import SubmitMetadata from '../mutations/submit-metadata.jsx'
8
8
  import LoggedIn from '../../authentication/logged-in.jsx'
9
- import { hasEditPermissions, getProfile } from '../../authentication/profile.js'
9
+ import { hasEditPermissions, getProfile } from '../../authentication/profile'
10
10
  import { DatasetPageBorder } from './styles/dataset-page-border'
11
11
  import { HeaderRow3, HeaderRow4 } from './styles/header-row'
12
12
 
@@ -3,7 +3,7 @@ import { useCookies } from 'react-cookie'
3
3
  import DeleteDatasetForm from '../mutations/delete-dataset-form.jsx'
4
4
  import DeleteDataset from '../mutations/delete.jsx'
5
5
  import LoggedIn from '../../authentication/logged-in.jsx'
6
- import { getProfile } from '../../authentication/profile.js'
6
+ import { getProfile } from '../../authentication/profile'
7
7
  import AdminUser from '../../authentication/admin-user.jsx'
8
8
  import { RegularUser } from '../../authentication/regular-user'
9
9
  import { DatasetPageBorder } from './styles/dataset-page-border'
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { Link } from 'react-router-dom'
4
3
  import { Button } from '@openneuro/components/button'
5
4
 
6
5
  import { RemovePermissions } from '../mutations/remove-permissions'
@@ -140,7 +139,7 @@ Share.propTypes = {
140
139
  datasetId: PropTypes.string,
141
140
  permissions: PropTypes.object,
142
141
  reviewers: PropTypes.array,
143
- hasSnapshot: PropTypes.boolean,
142
+ hasSnapshot: PropTypes.bool,
144
143
  }
145
144
 
146
145
  export default Share
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from 'react'
2
- import PropTypes from 'prop-types'
3
- import semver from 'semver'
2
+ import semver, { ReleaseType } from 'semver'
4
3
  import SnapshotDataset from '../mutations/snapshot'
5
4
  import EditList from '../fragments/edit-list.jsx'
6
5
  import { Button } from '@openneuro/components/button'
@@ -38,7 +37,12 @@ export const NoErrors = ({ issues, children }) => {
38
37
  }
39
38
  }
40
39
 
41
- const SnapshotRoute = ({ datasetId, snapshots, issues, description }) => {
40
+ const SnapshotRoute = ({
41
+ datasetId,
42
+ snapshots,
43
+ issues,
44
+ description,
45
+ }): React.ReactElement => {
42
46
  const [changes, setChanges] = useState([])
43
47
  const [semanticLevel, setSemanticLevel] = useState('patch')
44
48
  const draftLicense = (description && description.License) || 'none'
@@ -48,7 +52,7 @@ const SnapshotRoute = ({ datasetId, snapshots, issues, description }) => {
48
52
  const latestSnapshot = snapshots.length && snapshots[snapshots.length - 1]
49
53
  const newVersion =
50
54
  snapshots.length && semver.valid(latestSnapshot.tag)
51
- ? semver.inc(latestSnapshot.tag, semanticLevel)
55
+ ? semver.inc(latestSnapshot.tag, semanticLevel as ReleaseType)
52
56
  : '1.0.0'
53
57
 
54
58
  const majorActive = semanticLevel === 'major' && 'active'
@@ -138,11 +142,4 @@ const SnapshotRoute = ({ datasetId, snapshots, issues, description }) => {
138
142
  )
139
143
  }
140
144
 
141
- SnapshotRoute.propTypes = {
142
- datasetId: PropTypes.string,
143
- snapshots: PropTypes.array,
144
- issues: PropTypes.array,
145
- description: PropTypes.object,
146
- }
147
-
148
145
  export default SnapshotRoute
@@ -1,4 +1,6 @@
1
+ import React from 'react'
1
2
  import styled from '@emotion/styled'
3
+ import '@emotion/react'
2
4
 
3
5
  export const DatasetPageBorder = styled.div`
4
6
  border: 1px solid #ccc;
@@ -1,4 +1,6 @@
1
+ import React from 'react'
1
2
  import styled from '@emotion/styled'
3
+ import '@emotion/react'
2
4
 
3
5
  export const DatasetPageTabContainer = styled.div`
4
6
  display: flex;
@@ -1,4 +1,6 @@
1
+ import React from 'react'
1
2
  import styled from '@emotion/styled'
3
+ import '@emotion/react'
2
4
 
3
5
  const headerRowStyle = `
4
6
  margin-top: 0;
@@ -55,7 +55,7 @@ export const TabRoutesDraft = ({ dataset, hasEdit }) => {
55
55
  datasetId={dataset.id}
56
56
  permissions={dataset.permissions}
57
57
  reviewers={dataset.reviewers}
58
- hasSnapshot={dataset.snapshots.length}
58
+ hasSnapshot={dataset.snapshots.length !== 0}
59
59
  />
60
60
  }
61
61
  />
@@ -108,13 +108,13 @@ export const SnapshotContainer: React.FC<SnapshotContainerProps> = ({
108
108
  modality={summary?.modalities[0]}>
109
109
  <FollowToggles>
110
110
  <FollowDataset
111
- profile={profile}
111
+ profile={profile !== null}
112
112
  datasetId={dataset.id}
113
113
  following={dataset.following}
114
114
  followers={dataset.followers.length}
115
115
  />
116
116
  <StarDataset
117
- profile={profile}
117
+ profile={profile !== null}
118
118
  datasetId={dataset.id}
119
119
  starred={dataset.starred}
120
120
  stars={dataset.stars.length}
@@ -2,7 +2,7 @@ import React, { FC, ReactElement } from 'react'
2
2
  import { gql } from '@apollo/client'
3
3
  import { Mutation } from '@apollo/client/react/components'
4
4
  import { WarnButton } from '@openneuro/components/warn-button'
5
- import { getProfile } from '../../authentication/profile.js'
5
+ import { getProfile } from '../../authentication/profile'
6
6
  import { useCookies } from 'react-cookie'
7
7
  import { USER_FRAGMENT } from './user-fragment'
8
8
 
@@ -0,0 +1,8 @@
1
+ import React from 'react'
2
+
3
+ const Faq = (): React.ReactElement => {
4
+ window.location.replace('https://docs.openneuro.org/faq')
5
+ return null
6
+ }
7
+
8
+ export default Faq
@@ -0,0 +1,86 @@
1
+ import React from 'react'
2
+ import styled from '@emotion/styled'
3
+ import { DataTable } from '../../components/data-table'
4
+ import { gql, useQuery } from '@apollo/client'
5
+ import { Loading } from '@openneuro/components/loading'
6
+ import { makeCsv } from '../../utils/csv'
7
+
8
+ const MetadataPageStyle = styled.div`
9
+ background: white;
10
+ overflow-x: scroll;
11
+ padding: 1em;
12
+ height: calc(100vh - 125px);
13
+ white-space: nowrap;
14
+ `
15
+
16
+ const MetadataPageButton = styled.button`
17
+ display: inline-block;
18
+ margin-right: 1em;
19
+ `
20
+
21
+ const METADATA_QUERY = gql`
22
+ query {
23
+ publicMetadata {
24
+ datasetId
25
+ datasetUrl
26
+ datasetName
27
+ firstSnapshotCreatedAt
28
+ latestSnapshotCreatedAt
29
+ dxStatus
30
+ tasksCompleted
31
+ trialCount
32
+ grantFunderName
33
+ grantIdentifier
34
+ studyDesign
35
+ studyDomain
36
+ studyLongitudinal
37
+ dataProcessed
38
+ species
39
+ associatedPaperDOI
40
+ openneuroPaperDOI
41
+ seniorAuthor
42
+ adminUsers
43
+ ages
44
+ modalities
45
+ affirmedDefaced
46
+ affirmedConsent
47
+ }
48
+ }
49
+ `
50
+
51
+ export function DatasetMetadata(): React.ReactElement {
52
+ const { loading, error, data } = useQuery(METADATA_QUERY, {
53
+ errorPolicy: 'all',
54
+ })
55
+ if (loading || error) {
56
+ return <Loading />
57
+ } else {
58
+ return (
59
+ <MetadataPageStyle>
60
+ <p>
61
+ <MetadataPageButton
62
+ role="button"
63
+ type="button"
64
+ className="on-button on-button--small on-button--primary icon-text"
65
+ aria-label="Download"
66
+ onClick={() =>
67
+ makeCsv(data?.publicMetadata, 'openneuro-metadata.csv')
68
+ }>
69
+ <i className="fa fa-download css-0" aria-hidden="true"></i>Download
70
+ CSV
71
+ </MetadataPageButton>
72
+ Metadata collected for all public datasets on OpenNeuro.
73
+ </p>
74
+ <DataTable
75
+ data={data?.publicMetadata}
76
+ downloadFilename="openneuro-metadata.csv"
77
+ hideColumns={[
78
+ '__typename',
79
+ 'datasetUrl',
80
+ 'affirmedDefaced',
81
+ 'affirmedConsent',
82
+ ]}></DataTable>
83
+ </MetadataPageStyle>
84
+ )
85
+ }
86
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Top level dataset queries only, mutations may cause refetches of these
3
+ */
4
+ import { gql } from '@apollo/client'
5
+ import * as DatasetQueryFragments from '../datalad/dataset/dataset-query-fragments.js'
6
+ import { DATASET_COMMENTS } from '../datalad/dataset/comments-fragments.js'
7
+
8
+ /**
9
+ * Generate the dataset page query
10
+ */
11
+ export const getDatasetPage = gql`
12
+ query dataset($datasetId: ID!) {
13
+ dataset(id: $datasetId) {
14
+ id
15
+ created
16
+ public
17
+ following
18
+ followers {
19
+ userId
20
+ }
21
+ starred
22
+ stars {
23
+ userId
24
+ }
25
+ worker
26
+ ...DatasetDraft
27
+ ...DatasetPermissions
28
+ ...DatasetSnapshots
29
+ ...DatasetIssues
30
+ ...DatasetMetadata
31
+ ...DatasetComments
32
+ uploader {
33
+ id
34
+ name
35
+ email
36
+ orcid
37
+ }
38
+ analytics {
39
+ downloads
40
+ views
41
+ }
42
+ derivatives {
43
+ name
44
+ s3Url
45
+ dataladUrl
46
+ local
47
+ }
48
+ onBrainlife
49
+ }
50
+ }
51
+ ${DatasetQueryFragments.DRAFT_FRAGMENT}
52
+ ${DatasetQueryFragments.PERMISSION_FRAGMENT}
53
+ ${DatasetQueryFragments.DATASET_SNAPSHOTS}
54
+ ${DatasetQueryFragments.DATASET_ISSUES}
55
+ ${DatasetQueryFragments.DATASET_METADATA}
56
+ ${DATASET_COMMENTS}
57
+ `
58
+
59
+ /**
60
+ * Add files fragment for draft route
61
+ */
62
+ export const getDraftPage = gql`
63
+ query dataset($datasetId: ID!) {
64
+ dataset(id: $datasetId) {
65
+ id
66
+ created
67
+ public
68
+ following
69
+ followers {
70
+ userId
71
+ }
72
+ starred
73
+ stars {
74
+ userId
75
+ }
76
+ reviewers {
77
+ id
78
+ expiration
79
+ }
80
+ worker
81
+ ...DatasetDraft
82
+ ...DatasetDraftFiles
83
+ ...DatasetPermissions
84
+ ...DatasetSnapshots
85
+ ...DatasetIssues
86
+ ...DatasetMetadata
87
+ ...DatasetComments
88
+ uploader {
89
+ id
90
+ name
91
+ email
92
+ orcid
93
+ }
94
+ analytics {
95
+ downloads
96
+ views
97
+ }
98
+ derivatives {
99
+ name
100
+ s3Url
101
+ dataladUrl
102
+ local
103
+ }
104
+ }
105
+ }
106
+ ${DatasetQueryFragments.DRAFT_FRAGMENT}
107
+ ${DatasetQueryFragments.DRAFT_FILES_FRAGMENT}
108
+ ${DatasetQueryFragments.PERMISSION_FRAGMENT}
109
+ ${DatasetQueryFragments.DATASET_SNAPSHOTS}
110
+ ${DatasetQueryFragments.DATASET_ISSUES}
111
+ ${DatasetQueryFragments.DATASET_METADATA}
112
+ ${DATASET_COMMENTS}
113
+ `
@@ -15,6 +15,7 @@ import { PETRedirect } from './pages/pet-redirect'
15
15
  import Citation from './pages/citation-page'
16
16
  import FourOFourPage from './errors/404page'
17
17
  import { ImportDataset } from './pages/import-dataset'
18
+ import { DatasetMetadata } from './pages/metadata/dataset-metadata'
18
19
 
19
20
  const AppRoutes: React.VoidFunctionComponent = () => (
20
21
  <Routes>
@@ -28,6 +29,7 @@ const AppRoutes: React.VoidFunctionComponent = () => (
28
29
  <Route path="/pet" element={<PETRedirect />} />
29
30
  <Route path="/cite" element={<Citation />} />
30
31
  <Route path="/import" element={<ImportDataset />} />
32
+ <Route path="/metadata" element={<DatasetMetadata />} />
31
33
  <Route path="/public" element={<Navigate to="/search" replace />} />
32
34
  <Route
33
35
  path="/saved"
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
  import { SearchParamsCtx } from '../search-params-ctx'
3
3
  import { render } from '@testing-library/react'
4
+ import { queries } from '@testing-library/dom'
4
5
 
5
6
  /**
6
7
  * Render with SearchParamsCtx state
@@ -1,4 +1,4 @@
1
- import { sortBy } from '@openneuro/components/mock-content'
1
+ import { sortBy } from '@openneuro/components/content'
2
2
 
3
3
  const datasetType_available = [
4
4
  { label: 'All Public', value: 'All Public' },
@@ -1,7 +1,7 @@
1
1
  import React, { FC } from 'react'
2
2
  import { Route, Routes } from 'react-router-dom'
3
3
  import SearchContainer from './search-container'
4
- import { portalContent } from '@openneuro/components/mock-content'
4
+ import { portalContent } from '@openneuro/components/content'
5
5
 
6
6
  const SearchRoutes: FC = () => (
7
7
  <Routes>
@@ -11,7 +11,7 @@ import {
11
11
  sqsJoinWithAND,
12
12
  joinWithOR,
13
13
  } from './es-query-builders'
14
- import { species_list } from '@openneuro/components/mock-content'
14
+ import { species_list } from '@openneuro/components/content'
15
15
 
16
16
  const searchQuery = gql`
17
17
  query advancedSearchDatasets(
@@ -1,4 +1,6 @@
1
+ import React from 'react'
1
2
  import { createMedia } from '@artsy/fresnel'
3
+ import '@artsy/fresnel/dist/Media'
2
4
 
3
5
  const AppMedia = createMedia({
4
6
  breakpoints: {
@@ -0,0 +1,41 @@
1
+ import { convertArrayToCSV } from '../csv'
2
+
3
+ describe('utils/csv', () => {
4
+ it('converts to a valid CSV', () => {
5
+ const obj = [
6
+ { exampleCol: 'test', exampleCol2: 'test2', __typename: 'example' },
7
+ { exampleCol: 'test4', exampleCol2: 'test3', __typename: 'example' },
8
+ ]
9
+ expect(convertArrayToCSV(obj)).toEqual(
10
+ 'exampleCol,exampleCol2\n"test","test2"\n"test4","test3"',
11
+ )
12
+ })
13
+ it('escapes comma values correctly', () => {
14
+ const obj = [
15
+ { exampleCol: 'test', modalities: 'PET,MRI', __typename: 'example' },
16
+ { exampleCol: 'test4', modalities: 'MRI', __typename: 'example' },
17
+ ]
18
+ expect(convertArrayToCSV(obj)).toEqual(
19
+ 'exampleCol,modalities\n"test","PET,MRI"\n"test4","MRI"',
20
+ )
21
+ })
22
+ it('escapes double quotes', () => {
23
+ const obj = [
24
+ {
25
+ exampleCol: 'test',
26
+ modalities: 'PET,MRI',
27
+ name: 'A "Dataset"',
28
+ __typename: 'example',
29
+ },
30
+ {
31
+ exampleCol: 'test4',
32
+ modalities: 'MRI',
33
+ name: 'Another Dataset',
34
+ __typename: 'example',
35
+ },
36
+ ]
37
+ expect(convertArrayToCSV(obj)).toEqual(
38
+ 'exampleCol,modalities,name\n"test","PET,MRI","A ""Dataset"""\n"test4","MRI","Another Dataset"',
39
+ )
40
+ })
41
+ })