@openneuro/app 4.20.6 → 4.21.0-alpha.3

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 (42) hide show
  1. package/package.json +4 -4
  2. package/src/scripts/app.tsx +16 -10
  3. package/src/scripts/components/__tests__/agreement.spec.tsx +24 -0
  4. package/src/scripts/components/agreement.tsx +76 -0
  5. package/src/scripts/dataset/__tests__/__snapshots__/snapshot-container.spec.tsx.snap +10 -354
  6. package/src/scripts/dataset/components/BrainLifeButton.tsx +38 -0
  7. package/src/scripts/dataset/components/CloneDropdown.tsx +31 -0
  8. package/src/scripts/dataset/components/DatasetAlert.tsx +25 -0
  9. package/src/scripts/dataset/components/DatasetGitAccess.tsx +82 -0
  10. package/src/scripts/dataset/components/DatasetHeader.tsx +43 -0
  11. package/src/scripts/dataset/components/DatasetHeaderMeta.tsx +22 -0
  12. package/src/scripts/dataset/components/DatasetToolButton.tsx +52 -0
  13. package/src/scripts/dataset/components/DatasetTools.tsx +149 -0
  14. package/src/scripts/dataset/components/MetaDataBlock.tsx +24 -0
  15. package/src/scripts/dataset/components/MetaDataListBlock.tsx +23 -0
  16. package/src/scripts/dataset/components/ModalitiesMetaDataBlock.tsx +32 -0
  17. package/src/scripts/dataset/components/NemarButton.tsx +34 -0
  18. package/src/scripts/dataset/components/ValidationBlock.tsx +11 -0
  19. package/src/scripts/dataset/components/VersionList.tsx +115 -0
  20. package/src/scripts/dataset/components/__tests__/DatasetAlert.spec.tsx +25 -0
  21. package/src/scripts/dataset/components/__tests__/DatasetHeaders.spec.tsx +18 -0
  22. package/src/scripts/dataset/components/__tests__/DatasetTools.spec.tsx +133 -0
  23. package/src/scripts/dataset/draft-container.tsx +9 -11
  24. package/src/scripts/dataset/files/__tests__/file.spec.jsx +13 -4
  25. package/src/scripts/dataset/files/file.tsx +27 -21
  26. package/src/scripts/dataset/fragments/dataset-alert-draft.tsx +1 -1
  27. package/src/scripts/dataset/fragments/dataset-alert-version.tsx +1 -1
  28. package/src/scripts/dataset/routes/dataset-default.tsx +1 -1
  29. package/src/scripts/dataset/routes/download-dataset.tsx +7 -1
  30. package/src/scripts/dataset/routes/snapshot-default.tsx +1 -1
  31. package/src/scripts/dataset/snapshot-container.tsx +10 -12
  32. package/src/scripts/scss/README.md +3 -0
  33. package/src/scripts/scss/dataset/comments.scss +152 -0
  34. package/src/scripts/scss/dataset/dataset-page.scss +397 -0
  35. package/src/scripts/scss/dataset/dataset-tool.scss +281 -0
  36. package/src/scripts/scss/dataset/dropdown.scss +29 -0
  37. package/src/scripts/scss/dataset/validation.scss +392 -0
  38. package/src/scripts/scss/dataset/version-dropdown.scss +121 -0
  39. package/src/scripts/scss/index.scss +6 -0
  40. package/src/scripts/scss/variables.scss +205 -0
  41. package/src/scripts/utils/__tests__/local-storage.spec.tsx +32 -0
  42. package/src/scripts/utils/local-storage.tsx +53 -0
@@ -0,0 +1,133 @@
1
+ import React from "react"
2
+ import { render, screen } from "@testing-library/react"
3
+ import { MemoryRouter } from "react-router-dom"
4
+ import { DatasetTools } from "../DatasetTools"
5
+ import { LocalStorageProvider } from "../../../utils/local-storage"
6
+
7
+ const wrapper = ({ children }) => (
8
+ <MemoryRouter>
9
+ <LocalStorageProvider defaultValue={{ agreement: true }}>
10
+ {children}
11
+ </LocalStorageProvider>
12
+ </MemoryRouter>
13
+ )
14
+
15
+ describe("DatasetTools component", () => {
16
+ it("provides expected tools for a draft (admin)", () => {
17
+ render(
18
+ <DatasetTools
19
+ hasEdit={true}
20
+ isPublic={true}
21
+ isAdmin={true}
22
+ datasetId={"test000001"}
23
+ hasSnapshot={true}
24
+ isDatasetAdmin={true}
25
+ />,
26
+ { wrapper },
27
+ )
28
+ expect(screen.queryByLabelText("Files")).toBeInTheDocument()
29
+ expect(screen.queryByLabelText("Share")).toBeInTheDocument()
30
+ expect(screen.queryByLabelText("Versioning")).toBeInTheDocument()
31
+ expect(screen.queryByLabelText("Admin")).toBeInTheDocument()
32
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
33
+ expect(screen.queryByLabelText("Metadata")).toBeInTheDocument()
34
+ expect(screen.queryByLabelText("Delete")).toBeInTheDocument()
35
+ expect(screen.queryByLabelText("View Draft")).not.toBeInTheDocument()
36
+ })
37
+ it("provides expected tools for a snapshot (admin)", () => {
38
+ render(
39
+ <DatasetTools
40
+ hasEdit={true}
41
+ isPublic={true}
42
+ isAdmin={true}
43
+ snapshotId={"1.0.0"}
44
+ datasetId={"test000001"}
45
+ hasSnapshot={true}
46
+ isDatasetAdmin={true}
47
+ />,
48
+ { wrapper },
49
+ )
50
+ expect(screen.queryByLabelText("Files")).toBeInTheDocument()
51
+ expect(screen.queryByLabelText("View Draft")).toBeInTheDocument()
52
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
53
+ expect(screen.queryByLabelText("Metadata")).toBeInTheDocument()
54
+ expect(screen.queryByLabelText("Deprecate Version")).toBeInTheDocument()
55
+ expect(screen.queryByLabelText("Delete")).not.toBeInTheDocument()
56
+ })
57
+ it("provides expected tools for a draft (read only)", () => {
58
+ render(
59
+ <DatasetTools
60
+ hasEdit={false}
61
+ isPublic={true}
62
+ isAdmin={false}
63
+ datasetId={"test000001"}
64
+ hasSnapshot={true}
65
+ isDatasetAdmin={false}
66
+ />,
67
+ { wrapper },
68
+ )
69
+ expect(screen.queryByLabelText("Files")).toBeInTheDocument()
70
+ expect(screen.queryByLabelText("View Draft")).not.toBeInTheDocument()
71
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
72
+ expect(screen.queryByLabelText("Metadata")).toBeInTheDocument()
73
+ expect(screen.queryByLabelText("Deprecate Version")).not.toBeInTheDocument()
74
+ expect(screen.queryByLabelText("Delete")).not.toBeInTheDocument()
75
+ })
76
+ it("provides expected tools for a snapshot (read only)", () => {
77
+ render(
78
+ <DatasetTools
79
+ hasEdit={false}
80
+ isPublic={true}
81
+ isAdmin={false}
82
+ snapshotId={"1.0.0"}
83
+ datasetId={"test000001"}
84
+ hasSnapshot={true}
85
+ isDatasetAdmin={false}
86
+ />,
87
+ { wrapper },
88
+ )
89
+ expect(screen.queryByLabelText("Files")).toBeInTheDocument()
90
+ expect(screen.queryByLabelText("View Draft")).not.toBeInTheDocument()
91
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
92
+ expect(screen.queryByLabelText("Metadata")).toBeInTheDocument()
93
+ expect(screen.queryByLabelText("Deprecate Version")).not.toBeInTheDocument()
94
+ expect(screen.queryByLabelText("Delete")).not.toBeInTheDocument()
95
+ })
96
+ it("links to draft page when snapshotId is undefined", () => {
97
+ render(
98
+ <DatasetTools
99
+ hasEdit={false}
100
+ isPublic={true}
101
+ isAdmin={false}
102
+ datasetId={"test000001"}
103
+ hasSnapshot={true}
104
+ isDatasetAdmin={false}
105
+ />,
106
+ { wrapper },
107
+ )
108
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
109
+ expect(screen.queryByRole("link", { name: "Download" })).toHaveAttribute(
110
+ "href",
111
+ "/datasets/test000001/download",
112
+ )
113
+ })
114
+ it("links to snapshot page when snapshotId is defined", () => {
115
+ render(
116
+ <DatasetTools
117
+ hasEdit={false}
118
+ isPublic={true}
119
+ isAdmin={false}
120
+ datasetId={"test000001"}
121
+ snapshotId={"1.0.0"}
122
+ hasSnapshot={true}
123
+ isDatasetAdmin={false}
124
+ />,
125
+ { wrapper },
126
+ )
127
+ expect(screen.queryByLabelText("Download")).toBeInTheDocument()
128
+ expect(screen.queryByRole("link", { name: "Download" })).toHaveAttribute(
129
+ "href",
130
+ "/datasets/test000001/versions/1.0.0/download",
131
+ )
132
+ })
133
+ })
@@ -17,17 +17,15 @@ import {
17
17
  } from "../authentication/profile"
18
18
  import { useCookies } from "react-cookie"
19
19
  import { DatasetAlertDraft } from "./fragments/dataset-alert-draft"
20
- import {
21
- BrainLifeButton,
22
- CloneDropdown,
23
- DatasetGitAccess,
24
- DatasetHeader,
25
- DatasetTools,
26
- MetaDataBlock,
27
- ModalitiesMetaDataBlock,
28
- ValidationBlock,
29
- VersionList,
30
- } from "@openneuro/components/dataset"
20
+ import { BrainLifeButton } from "./components/BrainLifeButton"
21
+ import { CloneDropdown } from "./components/CloneDropdown"
22
+ import { DatasetGitAccess } from "./components/DatasetGitAccess"
23
+ import { DatasetHeader } from "./components/DatasetHeader"
24
+ import { DatasetTools } from "./components/DatasetTools"
25
+ import { MetaDataBlock } from "./components/MetaDataBlock"
26
+ import { ModalitiesMetaDataBlock } from "./components/ModalitiesMetaDataBlock"
27
+ import { ValidationBlock } from "./components/ValidationBlock"
28
+ import { VersionList } from "./components/VersionList"
31
29
  import { Username } from "../users/username"
32
30
 
33
31
  import { FollowDataset } from "./mutations/follow"
@@ -1,13 +1,22 @@
1
1
  import React from "react"
2
2
  import { render, screen } from "@testing-library/react"
3
3
  import { MemoryRouter } from "react-router-dom"
4
+ import { LocalStorageProvider } from "../../../utils/local-storage.tsx"
4
5
  import File from "../file"
5
6
 
7
+ const wrapper = ({ children }) => (
8
+ <MemoryRouter>
9
+ <LocalStorageProvider defaultValue={{ agreement: true }}>
10
+ {children}
11
+ </LocalStorageProvider>
12
+ </MemoryRouter>
13
+ )
14
+
6
15
  describe("File component", () => {
7
16
  it("renders with common props", () => {
8
17
  const { asFragment } = render(
9
18
  <File datasetId="ds001" path="" filename="README" size={500} />,
10
- { wrapper: MemoryRouter },
19
+ { wrapper },
11
20
  )
12
21
  expect(asFragment()).toMatchSnapshot()
13
22
  })
@@ -20,13 +29,13 @@ describe("File component", () => {
20
29
  filename="README"
21
30
  size={500}
22
31
  />,
23
- { wrapper: MemoryRouter },
32
+ { wrapper },
24
33
  )
25
34
  expect(asFragment()).toMatchSnapshot()
26
35
  })
27
36
  it("generates correct download links for top level files", () => {
28
37
  render(<File datasetId="ds001" path="" filename="README" size={500} />, {
29
- wrapper: MemoryRouter,
38
+ wrapper,
30
39
  })
31
40
  expect(screen.getByRole("link", { name: "download file" })).toHaveAttribute(
32
41
  "href",
@@ -41,7 +50,7 @@ describe("File component", () => {
41
50
  filename="sub-01_T1w.nii.gz"
42
51
  size={2000000}
43
52
  />,
44
- { wrapper: MemoryRouter },
53
+ { wrapper },
45
54
  )
46
55
  expect(screen.getByRole("link", { name: "download file" })).toHaveAttribute(
47
56
  "href",
@@ -11,6 +11,7 @@ import { getProfile, hasEditPermissions } from "../../authentication/profile"
11
11
  import { Icon } from "@openneuro/components/icon"
12
12
  import { Tooltip } from "@openneuro/components/tooltip"
13
13
  import { useCookies } from "react-cookie"
14
+ import { useAgreement } from "../../components/agreement"
14
15
 
15
16
  const filePath = (path, filename) => `${(path && path + ":") || ""}${filename}`
16
17
 
@@ -130,6 +131,7 @@ const File = ({
130
131
  filename,
131
132
  )
132
133
  }`
134
+ const [agreed] = useAgreement()
133
135
  const [cookies] = useCookies()
134
136
  const user = getProfile(cookies)
135
137
  return (
@@ -138,29 +140,33 @@ const File = ({
138
140
  &nbsp;&nbsp;
139
141
  {filename}
140
142
  <span className="filetree-editfile">
141
- <Media greaterThanOrEqual="medium">
142
- <Tooltip
143
- tooltip={`Download: ${bytes.format(Number(size)) as string}`}
144
- >
145
- <span className="edit-file download-file">
146
- <a
147
- href={urls?.[0] ||
148
- apiPath(datasetId, snapshotTag, filePath(path, filename))}
149
- download
150
- aria-label="download file"
151
- >
152
- <i className="fa fa-download" />
153
- </a>
143
+ {agreed && (
144
+ <Media greaterThanOrEqual="medium">
145
+ <Tooltip
146
+ tooltip={`Download: ${bytes.format(Number(size)) as string}`}
147
+ >
148
+ <span className="edit-file download-file">
149
+ <a
150
+ href={urls?.[0] ||
151
+ apiPath(datasetId, snapshotTag, filePath(path, filename))}
152
+ download
153
+ aria-label="download file"
154
+ >
155
+ <i className="fa fa-download" />
156
+ </a>
157
+ </span>
158
+ </Tooltip>
159
+ </Media>
160
+ )}
161
+ {agreed && (
162
+ <Tooltip tooltip="View">
163
+ <span className="edit-file view-file">
164
+ <Link to={viewerPath} aria-label="view file">
165
+ <i className="fa fa-eye" />
166
+ </Link>
154
167
  </span>
155
168
  </Tooltip>
156
- </Media>
157
- <Tooltip tooltip="View">
158
- <span className="edit-file view-file">
159
- <Link to={viewerPath} aria-label="view file">
160
- <i className="fa fa-eye" />
161
- </Link>
162
- </span>
163
- </Tooltip>
169
+ )}
164
170
  {editMode && (
165
171
  <Media greaterThanOrEqual="medium">
166
172
  <Tooltip tooltip="Update">
@@ -1,6 +1,6 @@
1
1
  import React from "react"
2
2
  import { Link } from "react-router-dom"
3
- import { DatasetAlert } from "@openneuro/components/dataset"
3
+ import { DatasetAlert } from "../components/DatasetAlert"
4
4
 
5
5
  export interface DatasetAlertDraftProps {
6
6
  isPrivate: boolean
@@ -1,5 +1,5 @@
1
1
  import React from "react"
2
- import { DatasetAlert } from "@openneuro/components/dataset"
2
+ import { DatasetAlert } from "../components/DatasetAlert"
3
3
  import { UndoDeprecateVersion } from "../mutations/undo-deprecate-version"
4
4
 
5
5
  export interface DatasetAlertVersionProps {
@@ -1,7 +1,7 @@
1
1
  import React from "react"
2
2
  import Markdown from "markdown-to-jsx"
3
3
  import { ReadMore } from "@openneuro/components/read-more"
4
- import { MetaDataBlock } from "@openneuro/components/dataset"
4
+ import { MetaDataBlock } from "../components/MetaDataBlock"
5
5
  import Files from "../files/files"
6
6
  import Comments from "../comments/comments"
7
7
  import EditDescriptionField from "../fragments/edit-description-field"
@@ -1,7 +1,7 @@
1
1
  /* global globalThis */
2
2
  import React from "react"
3
3
  import PropTypes from "prop-types"
4
- import { useParams } from "react-router-dom"
4
+ import { Navigate, useParams } from "react-router-dom"
5
5
  import DownloadLink from "../download/download-link.jsx"
6
6
  import DownloadS3 from "../download/download-s3.jsx"
7
7
  import DownloadCommandLine from "../download/download-command-line.jsx"
@@ -9,9 +9,15 @@ import DownloadDatalad from "../download/download-datalad.jsx"
9
9
  import { DatasetPageBorder } from "./styles/dataset-page-border"
10
10
  import { HeaderRow3 } from "./styles/header-row"
11
11
  import { DownloadScript } from "../download/download-script"
12
+ import { useAgreement } from "../../components/agreement"
12
13
 
13
14
  const DownloadDataset = ({ worker, datasetPermissions }) => {
14
15
  const { datasetId, tag: snapshotTag } = useParams()
16
+ const [agreed] = useAgreement()
17
+ // If the download page is directly visited without the agreement, return to the dataset page
18
+ if (!agreed) {
19
+ return <Navigate to={`/datasets/${datasetId}`} replace={true} />
20
+ }
15
21
  const workerId = worker?.split("-").pop()
16
22
  return (
17
23
  <DatasetPageBorder>
@@ -1,7 +1,7 @@
1
1
  import React from "react"
2
2
  import Markdown from "markdown-to-jsx"
3
3
  import { ReadMore } from "@openneuro/components/read-more"
4
- import { MetaDataBlock } from "@openneuro/components/dataset"
4
+ import { MetaDataBlock } from "../components/MetaDataBlock"
5
5
  import Files from "../files/files"
6
6
  import Comments from "../comments/comments"
7
7
 
@@ -13,18 +13,16 @@ import { config } from "../config"
13
13
  import DatasetCitation from "./fragments/dataset-citation.jsx"
14
14
  import { DatasetAlertVersion } from "./fragments/dataset-alert-version"
15
15
 
16
- import {
17
- BrainLifeButton,
18
- CloneDropdown,
19
- DatasetGitAccess,
20
- DatasetHeader,
21
- DatasetTools,
22
- MetaDataBlock,
23
- ModalitiesMetaDataBlock,
24
- NemarButton,
25
- ValidationBlock,
26
- VersionList,
27
- } from "@openneuro/components/dataset"
16
+ import { BrainLifeButton } from "./components/BrainLifeButton"
17
+ import { CloneDropdown } from "./components/CloneDropdown"
18
+ import { DatasetGitAccess } from "./components/DatasetGitAccess"
19
+ import { DatasetHeader } from "./components/DatasetHeader"
20
+ import { DatasetTools } from "./components/DatasetTools"
21
+ import { MetaDataBlock } from "./components/MetaDataBlock"
22
+ import { ModalitiesMetaDataBlock } from "./components/ModalitiesMetaDataBlock"
23
+ import { ValidationBlock } from "./components/ValidationBlock"
24
+ import { VersionList } from "./components/VersionList"
25
+ import { NemarButton } from "./components/NemarButton"
28
26
  import { Username } from "../users/username"
29
27
  import { Loading } from "@openneuro/components/loading"
30
28
 
@@ -0,0 +1,3 @@
1
+ Adding to the global SASS should be avoided if possible. New styles should be added as reusable components with the [Emotion package](https://emotion.sh).
2
+
3
+ These global styles cross many components that haven't been refactored. Style changes that can do this would allow for more isolated component styles with less chance of breaking on cross component changes.
@@ -0,0 +1,152 @@
1
+ /*Globals*/
2
+ .RichEditor-root {
3
+ background: #f9f9f9;
4
+ padding: 10px;
5
+ border-radius: 4px;
6
+ border: 1px solid #ddd;
7
+ }
8
+
9
+ .comment-reply .RichEditor-root {
10
+ border: 0;
11
+ border-radius: 0;
12
+ border-bottom: 1px solid #ddd;
13
+ }
14
+
15
+ .RichEditor-editor {
16
+ cursor: text;
17
+ font-size: 16px;
18
+ margin-top: 10px;
19
+ }
20
+
21
+ .RichEditor-editor .public-DraftEditorPlaceholder-root {
22
+ padding: 3px;
23
+ margin: 0 -10px;
24
+ background: #f9f9f9;
25
+ color: #000;
26
+ cursor: default;
27
+ }
28
+ .RichEditor-editor .public-DraftEditor-content {
29
+ min-height: 6em;
30
+ padding: 5px 3px;
31
+ }
32
+
33
+ .RichEditor-controls {
34
+ font-size: 14px;
35
+ margin-bottom: 5px;
36
+ user-select: none;
37
+ text-align: left;
38
+ display: flex;
39
+ flex-wrap: wrap;
40
+ }
41
+
42
+ .RichEditor-styleButton {
43
+ color: #000;
44
+ cursor: pointer;
45
+ margin-right: 10px;
46
+ padding: 5px;
47
+ border: 2px solid transparent;
48
+ display: block;
49
+ }
50
+
51
+ .RichEditor-activeButton {
52
+ color: var(--current-theme-primary);
53
+ border-color: var(--current-theme-primary);
54
+ }
55
+
56
+ // updated
57
+ .dataset-comments {
58
+ .comment-header {
59
+ label {
60
+ font-size: 18px;
61
+ color: #424242;
62
+ line-height: 10px;
63
+ padding: 0;
64
+ }
65
+ }
66
+ }
67
+
68
+ .comment-input {
69
+ width: 80%;
70
+ }
71
+
72
+ .deleted-comment {
73
+ padding: 15px;
74
+ }
75
+
76
+ .parent-comment {
77
+ margin-left: 0px;
78
+ padding-left: 0px;
79
+ border-left: none;
80
+ }
81
+
82
+ /*Editor Block*/
83
+ .DraftEditor-root {
84
+ padding: 0px 10px 10px 10px;
85
+ min-height: 2em;
86
+ }
87
+
88
+ .RichEditor-root > .RichEditor-editor > .DraftEditor-root {
89
+ min-height: 6em;
90
+ background-color: white;
91
+ // &:focus-within {
92
+ // box-shadow: inset 0px 0px 3px #666;
93
+ // }
94
+ }
95
+
96
+ .dataset-comments {
97
+ margin-bottom: 40px;
98
+ > .comment {
99
+ margin-top: 40px;
100
+ }
101
+ .comment {
102
+ border: 1px solid #eee;
103
+ border-bottom: 0;
104
+ background: white;
105
+ padding: 10px;
106
+ .comment-header {
107
+ font-size: 12px;
108
+ font-weight: 600;
109
+ margin-bottom: 20px;
110
+ }
111
+ .comment-controls {
112
+ font-size: 12px;
113
+ margin-top: 20px;
114
+ }
115
+ }
116
+
117
+ .replies {
118
+ background: white;
119
+
120
+ .replies {
121
+ border: 0;
122
+ border-top: 1px solid #eee;
123
+ border-left: 20px solid #eee;
124
+ }
125
+ .comment {
126
+ border: 0;
127
+ border-left: 20px solid #eee;
128
+ }
129
+ }
130
+ > .replies {
131
+ border: 1px solid #eee;
132
+ border-bottom: 0;
133
+ }
134
+ }
135
+
136
+ .dataset-owner-flag {
137
+ padding: 0px 2px;
138
+ background-color: red;
139
+
140
+ color: white;
141
+ }
142
+
143
+ .login-for-comments {
144
+ text-align: center;
145
+ }
146
+
147
+ .reply,
148
+ .delete,
149
+ .edit,
150
+ .cancel-edit {
151
+ padding-left: 1em;
152
+ }