@openneuro/app 5.1.0 → 5.1.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openneuro/app",
3
- "version": "5.1.0",
3
+ "version": "5.1.2",
4
4
  "description": "React JS web frontend for the OpenNeuro platform.",
5
5
  "license": "MIT",
6
6
  "main": "public/client.js",
@@ -79,5 +79,5 @@
79
79
  "publishConfig": {
80
80
  "access": "public"
81
81
  },
82
- "gitHead": "e3444f63f43cb7e9d3ecfac51d2a42cdcc4f4e60"
82
+ "gitHead": "bccaddf537a2950100549b992a846768c32d683e"
83
83
  }
@@ -64,7 +64,8 @@ export const GET_USER = gql`
64
64
  status
65
65
  }
66
66
  }
67
- orcidConsent
67
+ orcidConsent
68
+ profilePrivate
68
69
  }
69
70
  }
70
71
  `
@@ -74,22 +75,25 @@ export const UPDATE_USER = gql`
74
75
  mutation updateUser(
75
76
  $id: ID!
76
77
  $location: String
77
- $links: [String]
78
+ $links: [String!]
78
79
  $institution: String
79
- $orcidConsent: Boolean
80
+ $orcidConsent: Boolean
81
+ $profilePrivate: Boolean
80
82
  ) {
81
83
  updateUser(
82
84
  id: $id
83
85
  location: $location
84
86
  links: $links
85
87
  institution: $institution
86
- orcidConsent: $orcidConsent
88
+ orcidConsent: $orcidConsent
89
+ profilePrivate: $profilePrivate
87
90
  ) {
88
91
  id
89
92
  location
90
93
  links
91
94
  institution
92
95
  orcidConsent
96
+ profilePrivate
93
97
  }
94
98
  }
95
99
  `
@@ -20,6 +20,7 @@ export interface User {
20
20
  githubSynced?: Date
21
21
  notifications?: Event[]
22
22
  orcidConsent?: boolean | null
23
+ profilePrivate?: boolean
23
24
  }
24
25
 
25
26
  export interface UserRoutesProps {
@@ -0,0 +1,62 @@
1
+ import React, { useEffect, useState } from "react"
2
+ import * as Sentry from "@sentry/react"
3
+ import { useMutation } from "@apollo/client"
4
+ import { GET_USER, UPDATE_USER } from "../../queries/user"
5
+ import { RadioGroup } from "../../components/radio/RadioGroup"
6
+
7
+ export interface ProfilePrivacyProps {
8
+ userId: string
9
+ initialProfilePrivate: boolean
10
+ }
11
+
12
+ export const ProfilePrivacy: React.FC<ProfilePrivacyProps> = ({
13
+ userId,
14
+ initialProfilePrivate,
15
+ }) => {
16
+ const initialValue = initialProfilePrivate ? "true" : "false"
17
+ const [value, setValue] = useState(initialValue)
18
+
19
+ useEffect(() => {
20
+ setValue(initialProfilePrivate ? "true" : "false")
21
+ }, [initialProfilePrivate])
22
+
23
+ const [updateUser] = useMutation(UPDATE_USER, {
24
+ refetchQueries: [{ query: GET_USER, variables: { userId } }],
25
+ onError: (error) => {
26
+ Sentry.captureException(error)
27
+ },
28
+ })
29
+
30
+ const handleChange = async (newValue: string) => {
31
+ setValue(newValue)
32
+ try {
33
+ await updateUser({
34
+ variables: { id: userId, profilePrivate: newValue === "true" },
35
+ })
36
+ } catch (error) {
37
+ Sentry.captureException(error)
38
+ }
39
+ }
40
+
41
+ const radioOptions = [
42
+ { label: "Public", value: "false" },
43
+ { label: "Private", value: "true" },
44
+ ]
45
+
46
+ return (
47
+ <div>
48
+ <p>
49
+ Set your profile to private to hide your profile page from public view.
50
+ Your datasets and contributions will still be visible based on each
51
+ dataset's published state.
52
+ </p>
53
+ <RadioGroup
54
+ name="profilePrivate"
55
+ layout="row"
56
+ radioArr={radioOptions}
57
+ selected={value}
58
+ setSelected={handleChange}
59
+ />
60
+ </div>
61
+ )
62
+ }
@@ -8,6 +8,7 @@ import styles from "./scss/useraccountview.module.scss"
8
8
  import { GitHubAuthButton } from "./github-auth-button"
9
9
  import type { UserAccountViewProps } from "../types/user-types"
10
10
  import { OrcidConsentForm } from "./components/orcid-consent-form"
11
+ import { ProfilePrivacy } from "./components/profile-privacy"
11
12
  import { validateHttpHttpsUrl } from "../utils/validationUtils"
12
13
  import { pageTitle } from "../resources/strings.js"
13
14
 
@@ -115,20 +116,24 @@ export const UserAccountView: React.FC<UserAccountViewProps> = ({
115
116
  {orcidUser.github}
116
117
  </li>
117
118
  )}
118
- <li>
119
- <GitHubAuthButton sync={orcidUser.githubSynced} />
120
- </li>
119
+ {hasEdit && (
120
+ <li>
121
+ <GitHubAuthButton sync={orcidUser.githubSynced} />
122
+ </li>
123
+ )}
121
124
  </ul>
122
125
 
123
- <EditableContent
124
- editableContent={userLinks}
125
- setRows={handleLinksChange}
126
- heading="Links"
127
- validation={validateHttpHttpsUrl}
128
- validationMessage="Invalid URL format. Please start with http:// or https://"
129
- data-testid="links-section"
130
- hasEdit={hasEdit}
131
- />
126
+ {hasEdit && (
127
+ <div className={styles.umbOrcidConsent}>
128
+ <div className={styles.umbOrcidHeading}>
129
+ <h4>Profile Privacy</h4>
130
+ </div>
131
+ <ProfilePrivacy
132
+ userId={orcidUser.id}
133
+ initialProfilePrivate={orcidUser.profilePrivate ?? false}
134
+ />
135
+ </div>
136
+ )}
132
137
 
133
138
  {hasEdit && orcidUser.orcid !== undefined && (
134
139
  <div className={styles.umbOrcidConsent}>
@@ -142,6 +147,15 @@ export const UserAccountView: React.FC<UserAccountViewProps> = ({
142
147
  </div>
143
148
  )}
144
149
 
150
+ <EditableContent
151
+ editableContent={userLinks}
152
+ setRows={handleLinksChange}
153
+ heading="Links"
154
+ validation={validateHttpHttpsUrl}
155
+ validationMessage="Invalid URL format. Please start with http:// or https://"
156
+ data-testid="links-section"
157
+ hasEdit={hasEdit}
158
+ />
145
159
  <EditableContent
146
160
  editableContent={userLocation}
147
161
  setRows={handleLocationChange}
@@ -1,6 +1,8 @@
1
1
  import React, { useCallback, useEffect, useState } from "react"
2
2
  import { useQuery } from "@apollo/client"
3
3
  import * as Sentry from "@sentry/react"
4
+ import Helmet from "react-helmet"
5
+ import { pageTitle } from "../resources/strings"
4
6
  import { DatasetCard } from "./dataset-card"
5
7
  import { UserDatasetFilters } from "./components/user-dataset-filters"
6
8
  import { ADVANCED_SEARCH_DATASETS_QUERY } from "../queries/user"
@@ -260,6 +262,11 @@ export const UserDatasetsView: React.FC<UserDatasetsViewProps> = ({
260
262
  className={styles.userDatasetsWrapper}
261
263
  data-testid="user-datasets-view"
262
264
  >
265
+ <Helmet>
266
+ <title>
267
+ {orcidUser.name || "User"}'s Datasets - {pageTitle}
268
+ </title>
269
+ </Helmet>
263
270
  <h3>{orcidUser.name}'s Datasets</h3>
264
271
 
265
272
  <UserDatasetFilters
@@ -7,6 +7,7 @@ import { isAdmin } from "../authentication/admin-user"
7
7
  import { useCookies } from "react-cookie"
8
8
  import { getProfile } from "../authentication/profile"
9
9
  import { useUser } from "../queries/user"
10
+ import FourOThreePage from "../errors/403page"
10
11
 
11
12
  export const UserQuery: React.FC = () => {
12
13
  const { orcid } = useParams()
@@ -22,6 +23,10 @@ export const UserQuery: React.FC = () => {
22
23
 
23
24
  if (loading) return <div>Loading...</div>
24
25
 
26
+ if (!profile?.admin && user.profilePrivate) {
27
+ return <FourOThreePage />
28
+ }
29
+
25
30
  // is admin or profile matches id from the user data being returned
26
31
  const isUser = (user?.id === profile?.sub) ? true : false
27
32
  const hasEdit = isAdminUser || (user?.id === profile?.sub) ? true : false