@openneuro/app 4.24.2 → 4.25.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openneuro/app",
3
- "version": "4.24.2",
3
+ "version": "4.25.0-alpha.0",
4
4
  "description": "React JS web frontend for the OpenNeuro platform.",
5
5
  "license": "MIT",
6
6
  "main": "public/client.js",
@@ -20,8 +20,8 @@
20
20
  "@emotion/react": "11.11.1",
21
21
  "@emotion/styled": "11.11.0",
22
22
  "@niivue/niivue": "0.34.0",
23
- "@openneuro/client": "^4.24.2",
24
- "@openneuro/components": "^4.24.2",
23
+ "@openneuro/client": "^4.25.0-alpha.0",
24
+ "@openneuro/components": "^4.25.0-alpha.0",
25
25
  "@tanstack/react-table": "^8.9.3",
26
26
  "bids-validator": "1.14.6",
27
27
  "bytes": "^3.0.0",
@@ -74,5 +74,5 @@
74
74
  "publishConfig": {
75
75
  "access": "public"
76
76
  },
77
- "gitHead": "40d36c06d07682624d5065d0affc43b23122d577"
77
+ "gitHead": "cb86a035f14433d4783991b586c0ab22f58ec7d8"
78
78
  }
Binary file
Binary file
@@ -194,7 +194,6 @@ export const SNAPSHOT_FIELDS = gql`
194
194
  }
195
195
  ...SnapshotIssues
196
196
  hexsha
197
- onBrainlife
198
197
  }
199
198
  ${SNAPSHOT_ISSUES}
200
199
  `
@@ -302,6 +302,99 @@ exports[`SnapshotContainer component > renders successfully 1`] = `
302
302
  </article>
303
303
  </div>
304
304
  </div>
305
+ <div
306
+ class="clone-dropdown css-1jpt4j3"
307
+ >
308
+ <div
309
+ class="undefined dropdown-wrapper"
310
+ >
311
+ <div
312
+ class="toggle "
313
+ >
314
+ <span>
315
+ <button
316
+ aria-label="Analyze"
317
+ class="on-button on-button--small on-button--primary clone-link"
318
+ role="button"
319
+ type="button"
320
+ >
321
+ Analyze
322
+ <i
323
+ class="fas fa-caret-up"
324
+ />
325
+ <i
326
+ class="fas fa-caret-down"
327
+ />
328
+ </button>
329
+ </span>
330
+ </div>
331
+ <div
332
+ class="menu collapsed"
333
+ role="menu"
334
+ >
335
+ <div
336
+ class="dataset-git-access"
337
+ >
338
+ <span>
339
+ <h4>
340
+ Analyze this dataset
341
+ </h4>
342
+ </span>
343
+ <p>
344
+ Work with OpenNeuro datasets using any of these third-party tools.
345
+ </p>
346
+ <hr />
347
+ <img
348
+ height="16"
349
+ src="/packages/openneuro-app/src/assets/external/brainlife.png"
350
+ width="16"
351
+ />
352
+
353
+ <a
354
+ href="https://brainlife.io/openneuro/ds001032/1.0.0"
355
+ target="_blank"
356
+ >
357
+ View on Brainlife.io
358
+ </a>
359
+ <p>
360
+ Brainlife.io is a free cloud platform for secure neuroscience data analysis.
361
+ </p>
362
+ <hr />
363
+ <img
364
+ height="16"
365
+ src="/packages/openneuro-app/src/assets/external/nemar.png"
366
+ width="16"
367
+ />
368
+
369
+ <a
370
+ href="https://nemar.org/dataexplorer/detail?dataset_id=ds001032"
371
+ target="_blank"
372
+ >
373
+ View on NEMAR
374
+ </a>
375
+ <p>
376
+ View and analyze this dataset on the NEMAR OpenNeuro portal for MEG, iEEG, and EEG data.
377
+ </p>
378
+ <hr />
379
+ <img
380
+ height="16"
381
+ src="/packages/openneuro-app/src/assets/external/cbrain.png"
382
+ width="16"
383
+ />
384
+
385
+ <a
386
+ href="https://portal.cbrain.mcgill.ca/openneuro/ds001032/versions/1.0.0"
387
+ target="_blank"
388
+ >
389
+ View on CBRAIN
390
+ </a>
391
+ <p>
392
+ CBRAIN is a web-based distributed computing platform for collaborative neuroimaging research.
393
+ </p>
394
+ </div>
395
+ </div>
396
+ </div>
397
+ </div>
305
398
  <div
306
399
  class="clone-dropdown"
307
400
  >
@@ -330,6 +423,7 @@ exports[`SnapshotContainer component > renders successfully 1`] = `
330
423
  </div>
331
424
  <div
332
425
  class="menu collapsed"
426
+ role="menu"
333
427
  >
334
428
  <div>
335
429
  <span>
@@ -1054,6 +1148,7 @@ OCI-1131441 (R. Poldrack, PI) in any publications.
1054
1148
  </div>
1055
1149
  <div
1056
1150
  class="menu collapsed"
1151
+ role="menu"
1057
1152
  >
1058
1153
  <div
1059
1154
  class="version-list-dropdown"
@@ -0,0 +1,98 @@
1
+ import React from "react"
2
+ import { Dropdown } from "@openneuro/components/dropdown"
3
+ import { Button } from "@openneuro/components/button"
4
+ import styled from "@emotion/styled"
5
+ import BrainlifeIcon from "../../../assets/external/brainlife.png"
6
+ import NemarIcon from "../../../assets/external/nemar.png"
7
+ import CbrainIcon from "../../../assets/external/cbrain.png"
8
+
9
+ export interface CloneDropdownProps {
10
+ datasetId: string
11
+ snapshotVersion: string
12
+ }
13
+
14
+ const AnalyzeDiv = styled.div`
15
+ padding-right: 1em;
16
+ `
17
+
18
+ export const AnalyzeDropdown: React.FC<CloneDropdownProps> = (
19
+ { datasetId, snapshotVersion },
20
+ ) => {
21
+ const brainlifeUrl =
22
+ `https://brainlife.io/openneuro/${datasetId}/${snapshotVersion}`
23
+ const nemarUrl =
24
+ `https://nemar.org/dataexplorer/detail?dataset_id=${datasetId}`
25
+ const cbrainUrl =
26
+ `https://portal.cbrain.mcgill.ca/openneuro/${datasetId}/versions/${snapshotVersion}`
27
+ return (
28
+ <AnalyzeDiv className="clone-dropdown">
29
+ <Dropdown
30
+ label={
31
+ <Button
32
+ className="clone-link"
33
+ primary={true}
34
+ size="small"
35
+ label="Analyze"
36
+ >
37
+ <i className="fas fa-caret-up"></i>
38
+ <i className="fas fa-caret-down"></i>
39
+ </Button>
40
+ }
41
+ >
42
+ <div className="dataset-git-access">
43
+ <span>
44
+ <h4>Analyze this dataset</h4>
45
+ </span>
46
+ <p>
47
+ Work with OpenNeuro datasets using any of these third-party tools.
48
+ </p>
49
+ <hr />
50
+ <img
51
+ src={BrainlifeIcon}
52
+ height="16"
53
+ width="16"
54
+ />{" "}
55
+ <a
56
+ href={brainlifeUrl}
57
+ target="_blank"
58
+ >
59
+ View on Brainlife.io
60
+ </a>
61
+ <p>
62
+ Brainlife.io is a free cloud platform for secure neuroscience data
63
+ analysis.
64
+ </p>
65
+ <hr />
66
+ <img
67
+ src={NemarIcon}
68
+ height="16"
69
+ width="16"
70
+ />{" "}
71
+ <a
72
+ href={nemarUrl}
73
+ target="_blank"
74
+ >
75
+ View on NEMAR
76
+ </a>
77
+ <p>
78
+ View and analyze this dataset on the NEMAR OpenNeuro portal for MEG,
79
+ iEEG, and EEG data.
80
+ </p>
81
+ <hr />
82
+ <img
83
+ src={CbrainIcon}
84
+ height="16"
85
+ width="16"
86
+ />{" "}
87
+ <a href={cbrainUrl} target="_blank">
88
+ View on CBRAIN
89
+ </a>
90
+ <p>
91
+ CBRAIN is a web-based distributed computing platform for
92
+ collaborative neuroimaging research.
93
+ </p>
94
+ </div>
95
+ </Dropdown>
96
+ </AnalyzeDiv>
97
+ )
98
+ }
@@ -0,0 +1,19 @@
1
+ import React from "react"
2
+ import { fireEvent, render, screen } from "@testing-library/react"
3
+ import { AnalyzeDropdown } from "../AnalyzeDropdown"
4
+
5
+ describe("AnalyzeDropdown component", () => {
6
+ it("opens when clicked", () => {
7
+ render(
8
+ <AnalyzeDropdown datasetId="ds000031" snapshotVersion="1.0.0" />,
9
+ )
10
+
11
+ const button = screen.getByRole("button")
12
+ const menu = screen.getByRole("menu")
13
+
14
+ expect(button).toBeVisible()
15
+ expect(menu).toHaveClass("collapsed")
16
+ fireEvent.click(button)
17
+ expect(menu).toHaveClass("expanded")
18
+ })
19
+ })
@@ -8,14 +8,6 @@ import { Loading } from "@openneuro/components/loading"
8
8
  import DatasetQueryContext from "../datalad/dataset/dataset-query-context.js"
9
9
  import DatasetContext from "../datalad/dataset/dataset-context.js"
10
10
  import DatasetRoutes from "./dataset-routes"
11
- import FilesSubscription from "../datalad/subscriptions/files-subscription.jsx"
12
- import usePermissionsSubscription from "../datalad/subscriptions/usePermissionsSubscription"
13
- import useSnapshotsUpdatedSubscriptions from "../datalad/subscriptions/useSnapshotsUpdatedSubscriptions"
14
- import useDatasetDeletedSubscription, {
15
- datasetDeletedToast,
16
- } from "../datalad/subscriptions/useDatasetDeletedSubscription.jsx"
17
- import useDraftSubscription from "../datalad/subscriptions/useDraftSubscription.js"
18
-
19
11
  import ErrorBoundary, {
20
12
  ErrorBoundaryAssertionFailureException,
21
13
  } from "../errors/errorBoundary.jsx"
@@ -41,15 +33,6 @@ export const DatasetQueryHook = ({ datasetId, draft }) => {
41
33
  nextFetchPolicy: "cache-first",
42
34
  },
43
35
  )
44
- usePermissionsSubscription([datasetId])
45
- useSnapshotsUpdatedSubscriptions(datasetId)
46
- useDatasetDeletedSubscription([datasetId], ({ data: subData }) => {
47
- if (subData && subData.datasetDeleted === datasetId) {
48
- navigate("/dashboard/datasets")
49
- datasetDeletedToast(datasetId, data?.dataset?.draft?.description?.Name)
50
- }
51
- })
52
- useDraftSubscription(datasetId)
53
36
 
54
37
  if (error) {
55
38
  if (error.message === "You do not have access to read this dataset.") {
@@ -94,7 +77,6 @@ export const DatasetQueryHook = ({ datasetId, draft }) => {
94
77
  }}
95
78
  >
96
79
  <DatasetRoutes dataset={data.dataset} />
97
- <FilesSubscription datasetId={datasetId} />
98
80
  </DatasetQueryContext.Provider>
99
81
  </ErrorBoundary>
100
82
  </DatasetContext.Provider>
@@ -15,7 +15,6 @@ import {
15
15
  } from "../authentication/profile"
16
16
  import { useCookies } from "react-cookie"
17
17
  import { DatasetAlertDraft } from "./fragments/dataset-alert-draft"
18
- import { BrainLifeButton } from "./components/BrainLifeButton"
19
18
  import { CloneDropdown } from "./components/CloneDropdown"
20
19
  import { DatasetGitAccess } from "./components/DatasetGitAccess"
21
20
  import { DatasetHeader } from "./components/DatasetHeader"
@@ -141,10 +140,6 @@ const DraftContainer: React.FC<DraftContainerProps> = ({ dataset }) => {
141
140
  issues={dataset.draft.issues}
142
141
  />
143
142
  </ValidationBlock>
144
- <BrainLifeButton
145
- datasetId={datasetId}
146
- onBrainlife={dataset.onBrainlife}
147
- />
148
143
  <CloneDropdown
149
144
  gitAccess={
150
145
  <DatasetGitAccess
@@ -10,8 +10,7 @@ import Validation from "../validation/validation.jsx"
10
10
  import { config } from "../config"
11
11
  import DatasetCitation from "./fragments/dataset-citation.jsx"
12
12
  import { DatasetAlertVersion } from "./fragments/dataset-alert-version"
13
-
14
- import { BrainLifeButton } from "./components/BrainLifeButton"
13
+ import { AnalyzeDropdown } from "./components/AnalyzeDropdown"
15
14
  import { CloneDropdown } from "./components/CloneDropdown"
16
15
  import { DatasetGitAccess } from "./components/DatasetGitAccess"
17
16
  import { DatasetHeader } from "./components/DatasetHeader"
@@ -21,7 +20,6 @@ import { MetaDataListBlock } from "./components/MetaDataListBlock"
21
20
  import { ModalitiesMetaDataBlock } from "./components/ModalitiesMetaDataBlock"
22
21
  import { ValidationBlock } from "./components/ValidationBlock"
23
22
  import { VersionList } from "./components/VersionList"
24
- import { NemarButton } from "./components/NemarButton"
25
23
  import { Username } from "../users/username"
26
24
  import { Loading } from "@openneuro/components/loading"
27
25
 
@@ -131,15 +129,8 @@ export const SnapshotContainer: React.FC<SnapshotContainerProps> = ({
131
129
  <ValidationBlock>
132
130
  <Validation datasetId={dataset.id} issues={snapshot.issues} />
133
131
  </ValidationBlock>
134
- <NemarButton
135
- datasetId={datasetId}
136
- onNemar={summary?.modalities.includes("EEG") ||
137
- summary?.modalities.includes("iEEG") ||
138
- summary?.modalities.includes("MEG")}
139
- />
140
- <BrainLifeButton
132
+ <AnalyzeDropdown
141
133
  datasetId={datasetId}
142
- onBrainlife={snapshot.onBrainlife}
143
134
  snapshotVersion={snapshot.tag}
144
135
  />
145
136
  <CloneDropdown
@@ -153,7 +153,6 @@ export const dataset = {
153
153
  __typename: "Analytic",
154
154
  },
155
155
  derivatives: [],
156
- onBrainlife: false,
157
156
  }
158
157
 
159
158
  export const snapshot = {
@@ -296,5 +295,4 @@ export const snapshot = {
296
295
  ],
297
296
  __typename: "Snapshot",
298
297
  hexsha: "d62fdc42e2a568a6f89e33d68d3ef343ff883e02",
299
- onBrainlife: false,
300
298
  }
@@ -45,7 +45,6 @@ export const getDatasetPage = gql`
45
45
  dataladUrl
46
46
  local
47
47
  }
48
- onBrainlife
49
48
  }
50
49
  }
51
50
  ${DatasetQueryFragments.DRAFT_FRAGMENT}
@@ -1,3 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`FilesSubscription > renders with common props 1`] = `<DocumentFragment />`;
@@ -1,78 +0,0 @@
1
- import React from "react"
2
- import { render } from "@testing-library/react"
3
- import { MockedProvider } from "@apollo/client/testing"
4
- import FilesSubscription, {
5
- deleteFilesReducer,
6
- updateFilesReducer,
7
- } from "../files-subscription.jsx"
8
-
9
- describe("FilesSubscription", () => {
10
- it("renders with common props", () => {
11
- const { asFragment } = render(<FilesSubscription datasetId="ds001" />, {
12
- wrapper: MockedProvider,
13
- })
14
- expect(asFragment()).toMatchSnapshot()
15
- })
16
- })
17
-
18
- describe("deleteFilesReducer", () => {
19
- let draft, filesToDelete
20
- beforeEach(() => {
21
- draft = {
22
- a: 1,
23
- files: [
24
- { filename: "deleted/file.txt" },
25
- { filename: "another_deleted_file.txt" },
26
- { filename: "path/to/file.txt" },
27
- { filename: "deleted/file/again/here" },
28
- ],
29
- steak: "sauce",
30
- }
31
- filesToDelete = [
32
- { filename: "deleted" },
33
- { filename: "another_deleted_file.txt" },
34
- ]
35
- })
36
- it("removes files from draft", () => {
37
- const output = deleteFilesReducer(filesToDelete, draft)
38
- expect(output).toEqual({
39
- a: 1,
40
- files: [{ filename: "path/to/file.txt" }],
41
- steak: "sauce",
42
- })
43
- })
44
- })
45
-
46
- describe("updateFilesReducer", () => {
47
- let draft, filesToUpdate
48
- beforeEach(() => {
49
- draft = {
50
- a: 1,
51
- files: [
52
- { filename: "updated/file.txt", id: "something" },
53
- { filename: "a.txt" },
54
- { filename: "b" },
55
- ],
56
- steak: "sauce",
57
- }
58
- filesToUpdate = [
59
- { filename: "updated:file.txt", id: "somethingelse" },
60
- { filename: "new:file.txt", id: "x" },
61
- { filename: "another:new:file", id: "y" },
62
- ]
63
- })
64
- it("removes files from draft", () => {
65
- const output = updateFilesReducer(filesToUpdate, draft)
66
- expect(output).toEqual({
67
- a: 1,
68
- files: [
69
- { filename: "updated/file.txt", id: "somethingelse" },
70
- { filename: "a.txt" },
71
- { filename: "b" },
72
- { filename: "new/file.txt", id: "x" },
73
- { filename: "another/new/file", id: "y" },
74
- ],
75
- steak: "sauce",
76
- })
77
- })
78
- })
@@ -1,105 +0,0 @@
1
- import React from "react"
2
- import PropTypes from "prop-types"
3
- import { Subscription } from "@apollo/client/react/components"
4
- import { gql } from "@apollo/client"
5
- import { DRAFT_FILES_FRAGMENT } from "../dataset/dataset-query-fragments.js"
6
- import { datasetCacheId } from "../mutations/cache-id.js"
7
- // import { datasetCacheId } from '../mutations/cache-id.js'
8
-
9
- const FILES_SUBSCRIPTION = gql`
10
- subscription filesUpdated($datasetId: ID!) {
11
- filesUpdated(datasetId: $datasetId) {
12
- action
13
- payload {
14
- id
15
- filename
16
- size
17
- directory
18
- }
19
- }
20
- }
21
- `
22
-
23
- /**
24
- * Remove file with given filename from draft
25
- * @param {Object[]} files - file to be deleted (see DatasetFile schema)
26
- * @param {Object} draft - current draft in apollo cache
27
- * @returns {Object} - updated version of draft
28
- */
29
- export const deleteFilesReducer = (files, draft) => {
30
- const pathMatch = files
31
- .map(({ filename }) => filename.split(":").join("\\/"))
32
- .join("|")
33
- return {
34
- ...draft,
35
- files: draft.files.filter((file) => !file.filename.match(pathMatch)),
36
- }
37
- }
38
-
39
- export const updateFilesReducer = (files, draft) => {
40
- files = files.map((file) => ({
41
- ...file,
42
- filename: file.filename.split(":").join("/"),
43
- }))
44
- const newFiles = []
45
- const draftFiles = [...draft.files]
46
- files.forEach((file) => {
47
- const updatedFileIndex = draftFiles.findIndex(
48
- (draftFile) =>
49
- draftFile.filename === file.filename || draftFile.id === file.id,
50
- )
51
- if (updatedFileIndex === -1) newFiles.push(file)
52
- else draftFiles[updatedFileIndex] = file
53
- })
54
- return {
55
- ...draft,
56
- files: [...draftFiles, ...newFiles],
57
- }
58
- }
59
-
60
- export const draftReducer = (draft, action, payload) => {
61
- switch (action) {
62
- case "DELETE":
63
- return deleteFilesReducer(payload, draft)
64
- case "UPDATE":
65
- return updateFilesReducer(payload, draft)
66
- default:
67
- return { ...draft }
68
- }
69
- }
70
-
71
- const FilesSubscription = ({ datasetId }) => (
72
- <Subscription
73
- subscription={FILES_SUBSCRIPTION}
74
- variables={{ datasetId }}
75
- onSubscriptionData={({ client, subscriptionData }) => {
76
- const { cache } = client
77
- if (subscriptionData.data.filesUpdated) {
78
- const { action, payload } = subscriptionData.data.filesUpdated
79
- if (action && payload) {
80
- const id = datasetCacheId(datasetId)
81
- const { draft } = cache.readFragment({
82
- id,
83
- fragment: DRAFT_FILES_FRAGMENT,
84
- })
85
- const updatedDraft = draftReducer(draft, action, payload)
86
- cache.writeFragment({
87
- id,
88
- fragment: DRAFT_FILES_FRAGMENT,
89
- data: {
90
- __typename: "Dataset",
91
- id: datasetId,
92
- draft: updatedDraft,
93
- },
94
- })
95
- }
96
- }
97
- }}
98
- />
99
- )
100
-
101
- FilesSubscription.propTypes = {
102
- datasetId: PropTypes.string,
103
- }
104
-
105
- export default FilesSubscription
@@ -1,30 +0,0 @@
1
- import React from "react"
2
- import { gql, useSubscription } from "@apollo/client"
3
-
4
- import { toast } from "react-toastify"
5
- import ToastContent from "../../common/partials/toast-content.jsx"
6
-
7
- const DATASET_DELETED_SUBSCRIPTION = gql`
8
- subscription datasetDeleted($datasetIds: [ID!]) {
9
- datasetDeleted(datasetIds: $datasetIds)
10
- }
11
- `
12
-
13
- const useDatasetDeletedSubscription = (datasetIds, cb) => {
14
- const result = useSubscription(DATASET_DELETED_SUBSCRIPTION, {
15
- variables: { datasetIds },
16
- shouldResubscribe: true,
17
- })
18
- cb(result)
19
- }
20
-
21
- export const datasetDeletedToast = (datasetId, name = datasetId) => {
22
- toast.warn(
23
- <ToastContent
24
- title="Deleting Dataset"
25
- body={`Dataset "${name}" is being removed.`}
26
- />,
27
- )
28
- }
29
-
30
- export default useDatasetDeletedSubscription
@@ -1,26 +0,0 @@
1
- import { gql, useSubscription } from "@apollo/client"
2
-
3
- import {
4
- DATASET_ISSUES,
5
- DRAFT_FRAGMENT,
6
- } from "../dataset/dataset-query-fragments.js"
7
-
8
- const DRAFT_SUBSCRIPTION = gql`
9
- subscription draftUpdated($datasetId: ID!) {
10
- draftUpdated(datasetId: $datasetId) {
11
- id
12
- ...DatasetDraft
13
- ...DatasetIssues
14
- }
15
- }
16
- ${DRAFT_FRAGMENT}
17
- ${DATASET_ISSUES}
18
- `
19
-
20
- const useDraftSubscription = (datasetId) =>
21
- useSubscription(DRAFT_SUBSCRIPTION, {
22
- variables: { datasetId },
23
- shouldResubscribe: true,
24
- })
25
-
26
- export default useDraftSubscription
@@ -1,21 +0,0 @@
1
- import { gql, useSubscription } from "@apollo/client"
2
-
3
- import { PERMISSION_FRAGMENT } from "../dataset/dataset-query-fragments.js"
4
-
5
- const PERMISSIONS_SUBSCRIPTION = gql`
6
- subscription permissionsUpdated($datasetIds: [ID!]) {
7
- permissionsUpdated(datasetIds: $datasetIds) {
8
- id
9
- ...DatasetPermissions
10
- }
11
- }
12
- ${PERMISSION_FRAGMENT}
13
- `
14
-
15
- const usePermissionsSubscription = (datasetIds) =>
16
- useSubscription(PERMISSIONS_SUBSCRIPTION, {
17
- variables: { datasetIds: datasetIds || ["NULL_ID"] },
18
- shouldResubscribe: true,
19
- })
20
-
21
- export default usePermissionsSubscription
@@ -1,21 +0,0 @@
1
- import { gql, useSubscription } from "@apollo/client"
2
-
3
- import { DATASET_SNAPSHOTS } from "../dataset/dataset-query-fragments.js"
4
-
5
- export const SNAPSHOTS_UPDATED_SUBSCRIPTION = gql`
6
- subscription snapshotsUpdated($datasetId: ID!) {
7
- snapshotsUpdated(datasetId: $datasetId) {
8
- id
9
- ...DatasetSnapshots
10
- }
11
- }
12
- ${DATASET_SNAPSHOTS}
13
- `
14
-
15
- const useSnapshotsUpdatedSubscription = (datasetId) =>
16
- useSubscription(SNAPSHOTS_UPDATED_SUBSCRIPTION, {
17
- variables: { datasetId },
18
- shouldResubscribe: true,
19
- })
20
-
21
- export default useSnapshotsUpdatedSubscription
@@ -1,38 +0,0 @@
1
- import React from "react"
2
- import { Tooltip } from "@openneuro/components/tooltip"
3
- import { Button } from "@openneuro/components/button"
4
-
5
- export interface BrainLifeButtonProps {
6
- datasetId: string
7
- snapshotVersion?: string
8
- onBrainlife: boolean
9
- }
10
-
11
- export const BrainLifeButton: React.FC<BrainLifeButtonProps> = ({
12
- datasetId,
13
- snapshotVersion,
14
- onBrainlife,
15
- }) => {
16
- const url = snapshotVersion
17
- ? `https://brainlife.io/openneuro/${datasetId}/${snapshotVersion}`
18
- : `https://brainlife.io/openneuro/${datasetId}`
19
- return (
20
- <>
21
- {onBrainlife && (
22
- <div className="brainlife-block">
23
- <Tooltip tooltip="Analyze on brainlife" flow="up">
24
- <Button
25
- className="brainlife-link"
26
- primary={true}
27
- size="small"
28
- onClick={() => {
29
- window.open(url, "_blank")
30
- }}
31
- label="brainlife.io"
32
- />
33
- </Tooltip>
34
- </div>
35
- )}
36
- </>
37
- )
38
- }
@@ -1,38 +0,0 @@
1
- import React from "react"
2
- import { Tooltip } from "@openneuro/components/tooltip"
3
- import { Button } from "@openneuro/components/button"
4
-
5
- export interface NemarButtonProps {
6
- datasetId: string
7
- onNemar: boolean
8
- }
9
-
10
- export const NemarButton: React.FC<NemarButtonProps> = ({
11
- datasetId,
12
- onNemar,
13
- }) => {
14
- const url = `https://nemar.org/dataexplorer/detail?dataset_id=${datasetId}`
15
- return (
16
- <>
17
- {onNemar && (
18
- <div className="brainlife-block">
19
- <Tooltip
20
- tooltip="View and analyze this dataset on the NEMAR OpenNeuro portal for MEG, iEEG, and EEG data"
21
- flow="up"
22
- wrapText={true}
23
- >
24
- <Button
25
- className="brainlife-link"
26
- primary={true}
27
- size="small"
28
- onClick={() => {
29
- window.open(url, "_blank")
30
- }}
31
- label="NEMAR"
32
- />
33
- </Tooltip>
34
- </div>
35
- )}
36
- </>
37
- )
38
- }