diff --git a/Examples.md b/Examples.md index e122161f2a..4772968000 100644 --- a/Examples.md +++ b/Examples.md @@ -52,7 +52,6 @@ To use the synapse markdown-it component you must pass it a wiki page id and an | wikiId: String | wikiId for the synapse page | | markdown: String | markdown that is to be rendered | | errorMessageView?: React.FunctionComponent | Should accept and render an error message to the string | -| token?: string | auth token from synapse | Example 1: Rendering a Synapse Wiki page without any markdown pre-loaded @@ -234,7 +233,6 @@ This card can be used in two ways - as a standard row renderer or as a 'Header' | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | sql: string | The sql to be run against Synapse | | unitDescription: string | Fills in 'Displaying 50 ', NOTE: If not specified then no label will render | -| token?: string | Authentication token | | limit?: number | Used to constrain the number of cards shown, defaults to Infinity | | secondaryLabelLimit?: number | Used to constraint the number of secondary labels shown, defaults to three | | type: string | Type of card to be rendered. | diff --git a/README.md b/README.md index 2e1bc57dbc..e8183123e6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,11 @@ This project helps you integrate your app with the Synapse API backend. Interested in contributing to this project? See [contributing](./CONTRIBUTING.md). -## Installation with npm +## Installation + +We provide multiple ways to add Synapse React Client to your project + +### NPM Run the following command:
`npm install synapse-react-client` @@ -28,7 +32,7 @@ If using Typescript then you'll need to create a file called "synapse-react-clie declare module "synapse-react-client" ``` -## Installation without npm or yarn +### Installation without npm or yarn To see an example index.html page with all the necessary imports view [here](./src/demo/SingleFileBuild/index.html) @@ -128,6 +132,12 @@ Note there are a number of CDNs required to finish this functionality- ``` +## Usage + +Virtually all components require a SynapseContext (exported....) + +Example: + ## Setting Endpoints ### Configuring endpoint destinations for repo and portal diff --git a/src/demo/containers/playground/Playground.tsx b/src/demo/containers/playground/Playground.tsx index f6a60cc754..0adb64067e 100644 --- a/src/demo/containers/playground/Playground.tsx +++ b/src/demo/containers/playground/Playground.tsx @@ -112,7 +112,6 @@ const App = ({
{ console.log('DownloadList updated') }} @@ -158,7 +157,7 @@ const App = ({ component={() => (
{' '} - {' '} + {' '}
)} /> @@ -167,7 +166,7 @@ const App = ({ exact={true} path={`${match.url}/ExternalFileHandleLink`} component={() => ( - + )} /> diff --git a/src/lib/containers/AddToDownloadListV2.tsx b/src/lib/containers/AddToDownloadListV2.tsx index 55a0ff4f92..a0ce0ba10e 100644 --- a/src/lib/containers/AddToDownloadListV2.tsx +++ b/src/lib/containers/AddToDownloadListV2.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useContext } from 'react' import { AddBatchOfFilesToDownloadListResponse, } from '../utils/synapseTypes/DownloadListV2/AddBatchOfFilesToDownloadListResponse' @@ -6,19 +6,20 @@ import { addFileToDownloadListV2, } from '../utils/SynapseClient' import IconSvg from './IconSvg' +import { SynapseContext } from '../utils/SynapseContext' export type AddToDownloadListV2Props = { - token?: string entityId: string entityVersionNumber?: number } const AddToDownloadListV2: React.FunctionComponent = (props) => { - const {token, entityId, entityVersionNumber} = props + const {entityId, entityVersionNumber} = props + const { accessToken } = useContext(SynapseContext) const addToDownloadListV2 = async () => { try { - const result:AddBatchOfFilesToDownloadListResponse = await addFileToDownloadListV2(entityId, entityVersionNumber, token) + const result:AddBatchOfFilesToDownloadListResponse = await addFileToDownloadListV2(entityId, entityVersionNumber, accessToken) if (result.numberOfFilesAdded === 1) console.log(`Successfully added ${entityId} (version=${entityVersionNumber}) to the Download List v2`) else diff --git a/src/lib/containers/CardContainer.tsx b/src/lib/containers/CardContainer.tsx index 8bdb91c5f1..bc0b36e764 100644 --- a/src/lib/containers/CardContainer.tsx +++ b/src/lib/containers/CardContainer.tsx @@ -35,7 +35,6 @@ export type CardContainerProps = { unitDescription?: string hasMoreData?: boolean showBarChart?: boolean - token?: string } & CardConfiguration export const CardContainer = (props: CardContainerProps) => { @@ -49,13 +48,11 @@ export const CardContainer = (props: CardContainerProps) => { secondaryLabelLimit = 3, showBarChart = true, title, - token, getLastQueryRequest, executeQueryRequest, hasMoreData, ...rest } = props - const queryRequest = props.getLastQueryRequest!() /** * Handle a click on next or previous @@ -89,7 +86,6 @@ export const CardContainer = (props: CardContainerProps) => { const tableEntityConcreteType = useGetInfoFromIds({ ids, type: 'ENTITY_HEADER', - token: props.token, }) // the cards only show the loading screen on initial load, this occurs when data is undefined if (!data) { @@ -153,7 +149,6 @@ export const CardContainer = (props: CardContainerProps) => { tableEntityConcreteType: tableEntityConcreteType[0] && tableEntityConcreteType[0].type, tableId: props.data?.queryResult.queryResults.tableId, - token, ...rest, } return renderCard(propsForCard, type) @@ -165,7 +160,6 @@ export const CardContainer = (props: CardContainerProps) => { {title &&

{title}

} {!title && unitDescription && showBarChart && ( { this.setState({ ...newState, @@ -229,7 +230,7 @@ export default class CardContainerLogic extends React.Component< }, } - SynapseClient.getQueryTableResults(initQueryRequest, this.props.token) + SynapseClient.getQueryTableResults(initQueryRequest, this.context.accessToken) .then((data: QueryResultBundle) => { const queryRequestWithoutCount = cloneDeep(initQueryRequest) queryRequestWithoutCount.partMask = @@ -258,12 +259,11 @@ export default class CardContainerLogic extends React.Component< */ public render() { // only forward the necessary props - const { sql, searchParams, token, ...rest } = this.props + const { sql, searchParams, ...rest } = this.props return ( = (props) => { - const {token, associatedObjectId, entityVersionNumber, associatedObjectType, fileHandleId, displayFileName} = props + const { accessToken } = useContext(SynapseContext) + const { associatedObjectId, entityVersionNumber, associatedObjectType, fileHandleId, displayFileName} = props const { ref, inView } = useInView() const [isExternalFile, setIsExternalFile] = useState(false) const [hasFileAccess, setHasFileAccess] = useState(false) @@ -43,7 +44,7 @@ const DirectDownload: React.FunctionComponent = (props) return () => { mounted = false } - }, [token, inView]) + }, [accessToken, inView]) const getDownloadLink = async () => { let preSignedURL @@ -54,7 +55,7 @@ const DirectDownload: React.FunctionComponent = (props) } else { const file = await getFileResult( fileEntity!, - token, + accessToken, false, true ) @@ -94,11 +95,11 @@ const DirectDownload: React.FunctionComponent = (props) includePreviewPreSignedURLs: false, requestedFiles: fileHandleAssociationList, } - return getFiles(batchFileRequest, token) + return getFiles(batchFileRequest, accessToken) } const getFileEntityFileHandle = () => { - return getEntity(token, associatedObjectId, entityVersionNumber) + return getEntity(accessToken, associatedObjectId, entityVersionNumber) .then( async (entity) => { // From file view @@ -107,7 +108,7 @@ const DirectDownload: React.FunctionComponent = (props) setFileEntity(entity as FileEntity) return getFileResult( // TODO: Why can we just use getFiles here? entity as FileEntity, - token, + accessToken, true, ).then((data) => { const fh = data.fileHandle diff --git a/src/lib/containers/DirectDownloadButton.tsx b/src/lib/containers/DirectDownloadButton.tsx index 8324162129..c3c07e683a 100644 --- a/src/lib/containers/DirectDownloadButton.tsx +++ b/src/lib/containers/DirectDownloadButton.tsx @@ -1,11 +1,11 @@ -import React from 'react' +import React, { useContext } from 'react' import { Button } from 'react-bootstrap' import { BatchFileRequest, FileHandleAssociation } from '../utils/synapseTypes' import { getFiles } from '../utils/SynapseClient' +import { SynapseContext } from '../utils/SynapseContext' export type DirectFileDownloadButtonProps = { id?: string - token: string fileHandleAssociation: FileHandleAssociation fileName: string | undefined className?: string @@ -13,11 +13,11 @@ export type DirectFileDownloadButtonProps = { } const DirectDownloadButton: React.FC = props => { - - const {id, token, fileHandleAssociation, className, variant, fileName} = props + const {id, fileHandleAssociation, className, variant, fileName} = props + const { accessToken } = useContext(SynapseContext) const getDownloadLink = async () => { - if (!fileHandleAssociation.fileHandleId || !token) return + if (!fileHandleAssociation.fileHandleId || !accessToken) return const batchFileRequest:BatchFileRequest = { requestedFiles: [fileHandleAssociation], @@ -26,7 +26,7 @@ const DirectDownloadButton: React.FC = props => { includePreviewPreSignedURLs: false } try { - const file = await getFiles(batchFileRequest, token) + const file = await getFiles(batchFileRequest, accessToken) const preSignedURL = file.requestedFiles[0].preSignedURL if (!preSignedURL) { console.log("Fail to get file download link") diff --git a/src/lib/containers/EntityForm.tsx b/src/lib/containers/EntityForm.tsx index a48e7f35f2..5e3e64eaf4 100644 --- a/src/lib/containers/EntityForm.tsx +++ b/src/lib/containers/EntityForm.tsx @@ -12,6 +12,7 @@ import { UserProfile, } from '../utils/synapseTypes/' import { getFileHandleContent } from '../utils/SynapseClient' +import { SynapseContext } from '../utils/SynapseContext' export type EntityFormProps = { // Provide the parent container (folder/project), that should contain a folder (named ) that this user can write to. @@ -19,7 +20,6 @@ export type EntityFormProps = { formSchemaEntityId: string // Synapse file that contains the form schema. formUiSchemaEntityId: string // Synapse file that contains the form ui schema. initFormData: boolean // If true, it indicates that you’d like to download and pre-fill the form with the user's previous response. - token?: string // user's access token synIdCallback: (synId: string) => void // callback. Once the form output has been saved to a FileEntity, will send synID back } type EntityFormState = { @@ -38,6 +38,7 @@ export default class EntityForm extends React.Component< EntityFormProps, EntityFormState > { + static contextType = SynapseContext; formRef: any constructor(props: EntityFormProps) { @@ -53,34 +54,27 @@ export default class EntityForm extends React.Component< this.refresh() } - componentDidUpdate(prevProps: any) { - const shouldUpdate = this.props.token !== prevProps.token - if (shouldUpdate) { - this.refresh() - } - } - submitForm = () => { this.formRef.current.submit() } refresh = () => { - if (this.props.token) { + if (this.context.accessToken) { const promises = [ - SynapseClient.getUserProfile(this.props.token), + SynapseClient.getUserProfile(this.context.accessToken), SynapseClient.getEntity( - this.props.token, + this.context.accessToken, this.props.formSchemaEntityId, ), SynapseClient.getEntity( - this.props.token, + this.context.accessToken, this.props.formUiSchemaEntityId, ), ] as Promise[] Promise.all(promises) .then(values => { const userprofile: UserProfile = values[0] - this.getTargetContainer(userprofile, this.props.token!).then( + this.getTargetContainer(userprofile, this.context.accessToken!).then( // @ts-ignore (targetContainerId: string) => { const formSchemaFileEntity: FileEntity = values[1] @@ -107,13 +101,13 @@ export default class EntityForm extends React.Component< const promises = [ SynapseClient.getFileResult( formSchemaFileEntity, - this.props.token!, + this.context.accessToken!, true, true ), SynapseClient.getFileResult( formUiSchemaFileEntity, - this.props.token!, + this.context.accessToken!, true, true ), @@ -160,18 +154,18 @@ export default class EntityForm extends React.Component< } let formData: any let currentFileEntity: FileEntity - SynapseClient.lookupChildEntity(entityLookupRequest, this.props.token) + SynapseClient.lookupChildEntity(entityLookupRequest, this.context.accessToken) .then((entityId: EntityId) => { // ok, found the existing file return SynapseClient.getEntity( - this.props.token, + this.context.accessToken, entityId.id, ).then(entity => { currentFileEntity = entity if (this.props.initFormData) { return SynapseClient.getFileResult( currentFileEntity, - this.props.token!, + this.context.accessToken!, true, true, ).then(async (existingFileData) => { @@ -259,7 +253,7 @@ export default class EntityForm extends React.Component< createEntityFile = (fileContentsBlob: Blob) => { const fileName = `${this.state.formSchema.title}.json` - SynapseClient.uploadFile(this.props.token, fileName, fileContentsBlob) + SynapseClient.uploadFile(this.context.accessToken, fileName, fileContentsBlob) .then(fileUploadComplete => { // do we need to create a new file entity, or update an existing file entity? const newFileHandleId = fileUploadComplete.fileHandleId @@ -267,7 +261,7 @@ export default class EntityForm extends React.Component< this.state.currentFileEntity.dataFileHandleId = newFileHandleId return SynapseClient.updateEntity( this.state.currentFileEntity, - this.props.token, + this.context.accessToken, ) } // else, it's a new file entity @@ -277,7 +271,7 @@ export default class EntityForm extends React.Component< concreteType: 'org.sagebionetworks.repo.model.FileEntity', dataFileHandleId: newFileHandleId, } - return SynapseClient.createEntity(newFileEntity, this.props.token) + return SynapseClient.createEntity(newFileEntity, this.context.accessToken) }) .then(fileEntity => { // by this point we've either found and updated the existing file entity, or created a new one. @@ -307,7 +301,7 @@ export default class EntityForm extends React.Component<
)} - {this.props.token && + {this.context.accessToken && !this.state.isLoading && !this.state.successfullyUploaded && this.state.formSchema && @@ -328,7 +322,7 @@ export default class EntityForm extends React.Component<
)} - {!this.state.error && this.props.token && this.state.isLoading && ( + {!this.state.error && this.context.accessToken && this.state.isLoading && ( Saving… diff --git a/src/lib/containers/EntityIdList.tsx b/src/lib/containers/EntityIdList.tsx index 5e7fe58570..10dc9e9bd4 100644 --- a/src/lib/containers/EntityIdList.tsx +++ b/src/lib/containers/EntityIdList.tsx @@ -1,16 +1,17 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { useInView } from 'react-intersection-observer' import { getEntityHeadersByIds } from '../utils/SynapseClient' +import { SynapseContext } from '../utils/SynapseContext' export type EntityIdListProps = { entityIdList: string[], - token: string | undefined } const EntityIdList: React.FC = props => { - const { entityIdList, token } = props + const { accessToken } = useContext(SynapseContext) + const { entityIdList } = props const [entityNameList, setEntityNameList] = useState("") const { ref, inView } = useInView() let mounted:boolean = true @@ -27,7 +28,7 @@ const EntityIdList: React.FC = props => { const getEntityTypes = async () => { if (!entityIdList.length) return - getEntityHeadersByIds(entityIdList, token).then((entity) =>{ + getEntityHeadersByIds(entityIdList, accessToken).then((entity) =>{ const list = entity.results.map(el => el.name).join(", ") setEntityNameList(list) }).catch(e => { diff --git a/src/lib/containers/ErrorBanner.tsx b/src/lib/containers/ErrorBanner.tsx index c99abbe5a5..5a44e25a85 100644 --- a/src/lib/containers/ErrorBanner.tsx +++ b/src/lib/containers/ErrorBanner.tsx @@ -1,9 +1,9 @@ -import * as React from 'react' import { SynapseClientError } from '../utils/SynapseClient' import SignInButton from './SignInButton' import { Alert } from 'react-bootstrap' +import { SynapseContext } from '../utils/SynapseContext' +import React, { useContext } from 'react' type ErrorProps = { - token?: string error?: string | Error | SynapseClientError | null } @@ -25,13 +25,11 @@ function isString(error: string | Error | SynapseClientError): error is string { return typeof error === 'string' } -export const ClientError = (props: { - error: SynapseClientError - token?: string -}) => { - const { error, token } = props - const loginError = (error.status === 403 || error.status === 401) && !token - const accessDenied = error.status === 403 && token +export const ClientError = (props: { error: SynapseClientError }) => { + const { accessToken } = useContext(SynapseContext) + const { error } = props + const loginError = (error.status === 403 || error.status === 401) && !accessToken + const accessDenied = error.status === 403 && accessToken return ( <> @@ -50,7 +48,7 @@ export const ClientError = (props: { } export const ErrorBanner = (props: ErrorProps) => { - const { error, token } = props + const { error } = props if (!error) { return <> @@ -75,9 +73,7 @@ export const ErrorBanner = (props: ErrorProps) => { transition={false} >

- {synapseClientError && ( - - )} + {synapseClientError && } {jsError && jsError.message} {stringError && stringError}

diff --git a/src/lib/containers/ExternalFileHandleLink.tsx b/src/lib/containers/ExternalFileHandleLink.tsx index 53667c53c7..14d80b04a0 100644 --- a/src/lib/containers/ExternalFileHandleLink.tsx +++ b/src/lib/containers/ExternalFileHandleLink.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { BatchFileRequest, FileHandleAssociateType, @@ -11,17 +11,18 @@ import { SynapseClient } from '../utils/' import { library } from '@fortawesome/fontawesome-svg-core' import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { SynapseContext } from '../utils/SynapseContext' library.add(faExternalLinkAlt) export type ExternalFileHandleLinkProps = { synId: string - token?: string className?: string } export const ExternalFileHandleLink = (props: ExternalFileHandleLinkProps) => { - const { synId, token, className } = props + const { accessToken } = useContext(SynapseContext) + const { synId, className } = props const [data, setData] = useState< | { fileEntity: FileEntity; externalFileHandle: ExternalFileHandle } | undefined @@ -30,7 +31,7 @@ export const ExternalFileHandleLink = (props: ExternalFileHandleLinkProps) => { const getEntity = async () => { try { const fileEntity = await SynapseClient.getEntity( - token, + accessToken, synId, ) assertIsFileEntity(fileEntity) @@ -46,7 +47,7 @@ export const ExternalFileHandleLink = (props: ExternalFileHandleLinkProps) => { includePreSignedURLs: false, includePreviewPreSignedURLs: false, } - const file = await SynapseClient.getFiles(batchFileRequest, token) + const file = await SynapseClient.getFiles(batchFileRequest, accessToken) const externalFileHandle = file.requestedFiles[0].fileHandle assertIsExternalFileHandle(externalFileHandle) setData({ @@ -58,7 +59,7 @@ export const ExternalFileHandleLink = (props: ExternalFileHandleLinkProps) => { } } getEntity() - }, [synId, token]) + }, [synId, accessToken]) const externalFileHandle = data?.externalFileHandle const fileEntity = data?.fileEntity diff --git a/src/lib/containers/Facets.tsx b/src/lib/containers/Facets.tsx index e2d61e63f6..8ce77b0081 100644 --- a/src/lib/containers/Facets.tsx +++ b/src/lib/containers/Facets.tsx @@ -301,7 +301,6 @@ class Facets extends React.Component { {!showBarChart && ( { // if file entity if ( @@ -59,18 +55,26 @@ export default class FileContentDownloadUploadDemo extends React.Component< updateFileContent = (event: React.MouseEvent) => { // create a new FileHandle, and update the FileEntity - if (this.props.token && this.state.targetEntity && this.state.fileContent) { + if ( + this.context.accessToken && + this.state.targetEntity && + this.state.fileContent + ) { this.setState({ isLoading: true }) const newFileContent = new Blob([this.state.fileContent], { type: 'text/plain', }) - uploadFile(this.props.token, this.state.targetEntity.name, newFileContent) + uploadFile( + this.context.accessToken, + this.state.targetEntity.name, + newFileContent, + ) .then((fileUploadComplete: FileUploadComplete) => { // now update the entity! if (this.state.targetEntity) { this.state.targetEntity.dataFileHandleId = fileUploadComplete.fileHandleId - updateEntity(this.state.targetEntity, this.props.token) + updateEntity(this.state.targetEntity, this.context.accessToken) .then((entity: Entity) => { const fileEntity = entity as FileEntity // updated the target entity, force it to get the updated entity diff --git a/src/lib/containers/FileUpload.md b/src/lib/containers/FileUpload.md index 5b3b4f337e..ea93e3e375 100644 --- a/src/lib/containers/FileUpload.md +++ b/src/lib/containers/FileUpload.md @@ -1,8 +1,7 @@ ```jsx <> { + uploadCallback={(resp) => { if (resp.success) { document.getElementById("demo-upload-file").textContent = `Your file "${resp.resp.fileName}" upload is successful!` } else { diff --git a/src/lib/containers/FileUpload.tsx b/src/lib/containers/FileUpload.tsx index fef8e75300..2cfe24c938 100644 --- a/src/lib/containers/FileUpload.tsx +++ b/src/lib/containers/FileUpload.tsx @@ -1,11 +1,11 @@ import * as React from 'react' import { Button } from 'react-bootstrap' import { uploadFile } from '../utils/SynapseClient' +import { SynapseContext } from '../utils/SynapseContext' import { FileUploadComplete } from '../utils/synapseTypes' export type FileUploadProps = { id?: string - token: string label?: string variant?: string // allow you to change the appearance of the button to link (see react bootstrap doc) uploadCallback?: Function @@ -13,8 +13,9 @@ export type FileUploadProps = { } const FileUpload: React.FC = props => { - const { id, token, variant, label="Browse...", uploadCallback, context } = props - const hiddenFileInput = React.useRef(null); + const { id, variant, label = 'Browse...', uploadCallback, context } = props + const { accessToken } = React.useContext(SynapseContext) + const hiddenFileInput = React.useRef(null) const clickHandler = () => { if (hiddenFileInput?.current!) { @@ -26,27 +27,39 @@ const FileUpload: React.FC = props => { if (e.target.files) { const file = e.target.files[0] try { - const resp:FileUploadComplete = await uploadFile(token, file.name, file) + const resp: FileUploadComplete = await uploadFile( + accessToken, + file.name, + file, + ) uploadCallback?.({ success: true, resp: resp, - context: context + context: context, }) - } catch (e) { - console.log("FileUpload: fail to upload file", e) + console.log('FileUpload: fail to upload file', e) uploadCallback?.({ success: false, - message: e + message: e, }) } } } - return (<> - - - ) + return ( + <> + + + + ) } -export default FileUpload \ No newline at end of file +export default FileUpload diff --git a/src/lib/containers/GenericCard.tsx b/src/lib/containers/GenericCard.tsx index b1a44b7124..35adeb7054 100644 --- a/src/lib/containers/GenericCard.tsx +++ b/src/lib/containers/GenericCard.tsx @@ -9,7 +9,12 @@ import { } from './CardContainerLogic' import { unCamelCase } from '../utils/functions/unCamelCase' import MarkdownSynapse from './MarkdownSynapse' -import { SelectColumn, ColumnModel, ColumnType, EntityColumnType } from '../utils/synapseTypes' +import { + SelectColumn, + ColumnModel, + ColumnType, + EntityColumnType, +} from '../utils/synapseTypes' import { SynapseConstants } from '../utils' import { FileHandleLink } from './widgets/FileHandleLink' import IconList from './IconList' @@ -20,6 +25,7 @@ import { } from '../utils/functions/RegularExpressions' import { SMALL_USER_CARD } from '../utils/SynapseConstants' import UserCard from './UserCard' +import { SynapseContext } from '../utils/SynapseContext' export type KeyToAlias = { key: string @@ -52,12 +58,11 @@ export type GenericCardProps = { selectColumns?: SelectColumn[] columnModels?: ColumnModel[] facetAliases?: {} - iconOptions?: IconOptions + iconOptions?: IconOptions isHeader?: boolean isAlignToLeftNav?: boolean schema: any data: any - token?: string tableEntityConcreteType: string | undefined tableId: string | undefined columnIconOptions?: {} @@ -106,8 +111,7 @@ export const getValueOrMultiValue = ({ const selectedColumnOrUndefined = selectColumns?.find(el => el.name === columnName) || columnModels?.find(el => el.name === columnName) - const isMultiValue = - selectedColumnOrUndefined?.columnType.endsWith('_LIST') + const isMultiValue = selectedColumnOrUndefined?.columnType.endsWith('_LIST') if (isMultiValue) { let val: any = value @@ -118,7 +122,7 @@ export const getValueOrMultiValue = ({ return { strList, str: val, - columnModelType: selectedColumnOrUndefined?.columnType + columnModelType: selectedColumnOrUndefined?.columnType, } } catch (e) { console.error( @@ -172,20 +176,18 @@ export const renderLabel = (args: { } // PORTALS-1913: special rendering for user ID lists if (columnModelType === 'USERID_LIST' && strList) { - return strList.map((val:string, index:number) => { - return ( - - - {/* \u00a0 is a nbsp; */} - {index < strList.length - 1 && ',\u00a0\u00a0'} - - ) + return strList.map((val: string, index: number) => { + return ( + + + {/* \u00a0 is a nbsp; */} + {index < strList.length - 1 && ',\u00a0\u00a0'} + + ) }) } if (columnModelType === 'USERID' && str) { - return ( - - ) + return } if (!labelLink) { @@ -241,7 +243,7 @@ export const renderLabel = (args: { type ValueOrMultiValue = { str: string - strList?: string[], + strList?: string[] columnModelType?: ColumnType | EntityColumnType } @@ -249,6 +251,8 @@ export default class GenericCard extends React.Component< GenericCardProps, GenericCardState > { + static contextType = SynapseContext + constructor(props: GenericCardProps) { super(props) this.state = { @@ -360,7 +364,7 @@ export default class GenericCard extends React.Component< schema, data, genericCardSchema, - secondaryLabelLimit, + secondaryLabelLimit, selectColumns, columnModels, iconOptions, @@ -374,7 +378,6 @@ export default class GenericCard extends React.Component< tableId, tableEntityConcreteType, columnIconOptions, - token, } = this.props // GenericCard inherits properties from CommonCardProps so that the properties have the same name // and type, but theres one nuance which is that we can't override if one specific property will be @@ -438,32 +441,45 @@ export default class GenericCard extends React.Component< const showFooter = values.length > 0 - const style: React.CSSProperties = { + const style: React.CSSProperties = { // undefined, take default value from class marginTop: isHeader ? '0px' : undefined, marginBottom: isHeader ? '0px' : undefined, paddingBottom: showFooter || imageFileHandleIdValue ? undefined : '15px', - } - const icon:JSX.Element = <> - {imageFileHandleIdValue &&
-
} - {!imageFileHandleIdValue &&
- -
} + } + const icon: JSX.Element = ( + <> + {imageFileHandleIdValue && ( +
+ +
+ )} + {!imageFileHandleIdValue && ( +
+ +
+ )} + ) if (isHeader) { return ( - + {ctaLinkConfig.text} @@ -605,11 +618,10 @@ export default class GenericCard extends React.Component< hasClickedShowMore: boolean, descriptionSubTitle: any, descriptionConfig?: DescriptionConfig, - token?: string, ): React.ReactNode { let content: JSX.Element | string = description if (descriptionConfig?.isMarkdown) { - content = + content = } const show = hasClickedShowMore || descriptionConfig?.showFullDescriptionByDefault diff --git a/src/lib/containers/HasAccess.md b/src/lib/containers/HasAccess.md index 8d11915bd8..af44a8c3df 100644 --- a/src/lib/containers/HasAccess.md +++ b/src/lib/containers/HasAccess.md @@ -1,5 +1,3 @@ ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/HasAccess.tsx b/src/lib/containers/HasAccess.tsx index 09b81f79ef..28122aa73d 100644 --- a/src/lib/containers/HasAccess.tsx +++ b/src/lib/containers/HasAccess.tsx @@ -49,6 +49,7 @@ import AccessRequirementList, { AccessRequirementListProps, } from './access_requirement_list/AccessRequirementList' import { SRC_SIGN_IN_CLASS } from '../utils/SynapseConstants' +import { SynapseContext } from '../utils/SynapseContext' library.add(faUnlockAlt) library.add(faDatabase) @@ -60,7 +61,6 @@ export type HasAccessProps = { entityId: string isInDownloadList?: boolean // set to show errors in UI about package creation entityVersionNumber?: string - token?: string forceSamePage?: boolean set_arPropsFromHasAccess?: (props: AccessRequirementListProps) => void } @@ -101,7 +101,10 @@ export const getDownloadTypeForFileHandle = ( return FileHandleDownloadTypeEnum.TooLarge } // check if it's a google cloud file handle - if (concreteType === CloudProviderFileHandleConcreteTypeEnum.GoogleCloudFileHandle) { + if ( + concreteType === + CloudProviderFileHandleConcreteTypeEnum.GoogleCloudFileHandle + ) { return FileHandleDownloadTypeEnum.ExternalCloudFile } // check if it's an external file handle @@ -142,6 +145,8 @@ export default class HasAccess extends React.Component< 'This file must be downloaded manually (e.g. a file in Google Cloud).', } + static contextType = SynapseContext + constructor(props: HasAccessProps) { super(props) this.getRestrictionInformation = this.getRestrictionInformation.bind(this) @@ -164,12 +169,6 @@ export default class HasAccess extends React.Component< this.refresh() } - componentDidUpdate(prevProps: HasAccessProps) { - const forceRefresh = prevProps.token !== this.props.token - // if there token has updated then force refresh the component state - this.refresh(forceRefresh) - } - refresh = (forceRefresh?: boolean) => { if ( this.state.isGettingEntityInformation || @@ -183,8 +182,7 @@ export default class HasAccess extends React.Component< } updateStateFileHandleAccessBlocked = () => { - const { token } = this.props - const fileHandleDownloadType = token + const fileHandleDownloadType = this.context.accessToken ? FileHandleDownloadTypeEnum.AccessBlockedByACL : FileHandleDownloadTypeEnum.AccessBlockedToAnonymous this.setState({ @@ -196,7 +194,6 @@ export default class HasAccess extends React.Component< const { entityId, entityVersionNumber, - token, isInDownloadList, fileHandle, } = this.props @@ -220,14 +217,18 @@ export default class HasAccess extends React.Component< }) // fileHandle was not passed to us, ask for it. // is this a FileEntity? - return SynapseClient.getEntity(token, entityId, entityVersionNumber) + return SynapseClient.getEntity( + this.context.accessToken, + entityId, + entityVersionNumber, + ) .then(entity => { if (entity.hasOwnProperty('dataFileHandleId')) { // looks like a FileEntity, get the FileHandle return SynapseClient.getFileResult( entity as FileEntity, - token, - true + this.context.accessToken, + true, ).then((fileHandle: FileResult) => { const fileHandleDownloadType = getDownloadTypeForFileHandle( fileHandle.fileHandle!, @@ -261,7 +262,7 @@ export default class HasAccess extends React.Component< } getRestrictionInformation = (forceRefresh?: boolean) => { - const { entityId, token } = this.props + const { entityId } = this.props if (this.state.restrictionInformation && !forceRefresh) { return } @@ -272,7 +273,10 @@ export default class HasAccess extends React.Component< restrictableObjectType: RestrictableObjectType.ENTITY, objectId: entityId, } - return SynapseClient.getRestrictionInformation(request, token) + return SynapseClient.getRestrictionInformation( + request, + this.context.accessToken, + ) .then(restrictionInformation => { this.setState({ restrictionInformation, @@ -345,36 +349,37 @@ export default class HasAccess extends React.Component< } handleGetAccess = () => { - const { token, entityId, set_arPropsFromHasAccess } = this.props - SynapseClient.getAllAccessRequirements(token, entityId).then( - requirements => { - if (checkHasUnsportedRequirement(requirements)) { - window.open( - `${getEndpoint( - BackendDestinationEnum.PORTAL_ENDPOINT, - )}#!AccessRequirements:ID=${entityId}&TYPE=ENTITY`, - '_blank', - ) + const { entityId, set_arPropsFromHasAccess } = this.props + SynapseClient.getAllAccessRequirements( + this.context.accessToken, + entityId, + ).then(requirements => { + if (checkHasUnsportedRequirement(requirements)) { + window.open( + `${getEndpoint( + BackendDestinationEnum.PORTAL_ENDPOINT, + )}#!AccessRequirements:ID=${entityId}&TYPE=ENTITY`, + '_blank', + ) + } else { + if (set_arPropsFromHasAccess) { + set_arPropsFromHasAccess({ + accessRequirementFromProps: requirements, + entityId, + }) } else { - if (set_arPropsFromHasAccess) { - set_arPropsFromHasAccess({ - accessRequirementFromProps: requirements, - entityId, - }) - } else { - this.setState({ - accessRequirements: requirements, - displayAccessRequirement: true, - }) - } + this.setState({ + accessRequirements: requirements, + displayAccessRequirement: true, + }) } - }, - ) + } + }) } // Show Access Requirements renderARsLink = () => { - const { entityId, token } = this.props + const { entityId } = this.props const { restrictionInformation, displayAccessRequirement, @@ -412,7 +417,6 @@ export default class HasAccess extends React.Component< {displayAccessRequirement && ( + ``` Or driven by a wiki page: ```jsx - + ``` Supports videos, images, and more. No need to provide the wiki page ID for most entities: ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/MarkdownSynapse.tsx b/src/lib/containers/MarkdownSynapse.tsx index 9fb9d99449..ddd041d0a9 100644 --- a/src/lib/containers/MarkdownSynapse.tsx +++ b/src/lib/containers/MarkdownSynapse.tsx @@ -9,6 +9,7 @@ import SynapseVideo from './widgets/SynapseVideo' import { ErrorBanner } from './ErrorBanner' import { SynapseClientError } from '../utils/SynapseClient' import { Button } from 'react-bootstrap' +import { SynapseContext } from '../utils/SynapseContext' const TOC_CLASS = { 1: 'toc-indent1', @@ -38,7 +39,6 @@ declare var sanitizeHtml: any declare var markdownitMath: any export type MarkdownSynapseProps = { - token?: string ownerId?: string wikiId?: string markdown?: string @@ -65,7 +65,7 @@ export default class MarkdownSynapse extends React.Component< MarkdownSynapseState > { public markupRef: React.RefObject - + static contextType = SynapseContext /** * Creates an instance of Markdown. * @param {*} props @@ -295,13 +295,13 @@ export default class MarkdownSynapse extends React.Component< * Get wiki page markdown and file attachment handles */ public async getWikiPageMarkdown() { - const { ownerId, wikiId, token, objectType } = this.props + const { ownerId, wikiId, objectType } = this.props if (!ownerId && !wikiId) { return } try { const wikiPage = await SynapseClient.getEntityWiki( - token, + this.context.accessToken, ownerId, wikiId, objectType, @@ -326,7 +326,7 @@ export default class MarkdownSynapse extends React.Component< } } public async getWikiAttachments(wikiId: string) { - const { token, ownerId, objectType } = this.props + const { ownerId, objectType } = this.props if (!ownerId) { console.error( 'Cannot get wiki attachments without ownerId on Markdown Component', @@ -334,7 +334,7 @@ export default class MarkdownSynapse extends React.Component< return undefined } return await SynapseClient.getWikiAttachmentsFromEntity( - token, + this.context.accessToken, ownerId, wikiId, objectType, @@ -580,8 +580,7 @@ export default class MarkdownSynapse extends React.Component< if (alignLowerCase === 'right') { buttonClasses += 'floatright ' } - const buttonVariant = - highlight === 'true' ? 'secondary' : 'light-secondary' + const buttonVariant = highlight === 'true' ? 'secondary' : 'light-secondary' if (alignLowerCase === 'center') { return (
+ return } public renderSynapseImage(widgetparamsMapped: any) { @@ -642,7 +638,6 @@ export default class MarkdownSynapse extends React.Component< ) @@ -710,8 +704,7 @@ export default class MarkdownSynapse extends React.Component< // on component update find and re-render the math/widget items accordingly public async componentDidUpdate(prevProps: MarkdownSynapseProps) { - let shouldUpdate = this.props.token !== prevProps.token - shouldUpdate = shouldUpdate || this.props.ownerId !== prevProps.ownerId + let shouldUpdate = this.props.ownerId !== prevProps.ownerId shouldUpdate = shouldUpdate || this.props.wikiId !== prevProps.wikiId // we have to carefully update the component so it doesn't encounter an infinite loop @@ -722,11 +715,11 @@ export default class MarkdownSynapse extends React.Component< } public render() { - const { renderInline, token } = this.props + const { renderInline } = this.props const { isLoading, error } = this.state if (error) { - return + return } const bookmarks = this.addBookmarks() const content = ( diff --git a/src/lib/containers/ModalDownload.tsx b/src/lib/containers/ModalDownload.tsx index e24ce7bda0..39d179aaa2 100644 --- a/src/lib/containers/ModalDownload.tsx +++ b/src/lib/containers/ModalDownload.tsx @@ -19,6 +19,7 @@ import { writeHeaderOption, } from './ModalDownload.FormSchema' import { parseEntityIdFromSqlStatement } from '../utils/functions/sqlFunctions' +import { SynapseContext } from '../utils/SynapseContext' library.add(faTimes) @@ -31,7 +32,6 @@ export type ModalDownloadState = { export type ModalDownloadProps = { onClose: (...args: any[]) => void - token?: string includeEntityEtag?: boolean queryBundleRequest?: QueryBundleRequest // either the query bundle request needs to be provided, or getLastQueryRequest getLastQueryRequest?: () => QueryBundleRequest @@ -44,6 +44,8 @@ export default class ModalDownload extends React.Component< ModalDownloadProps, ModalDownloadState > { + static contextType = SynapseContext + constructor(props: ModalDownloadProps) { super(props) this.state = { @@ -71,7 +73,7 @@ export default class ModalDownload extends React.Component< const { formData } = event const fileType = formData['File Type'] const contents = formData.Contents as string[] - const { token, queryBundleRequest, getLastQueryRequest } = this.props + const { queryBundleRequest, getLastQueryRequest } = this.props const separator = fileType === csvOption ? ',' : '\t' const writeHeader = contents.includes(writeHeaderOption) const includeRowIdAndRowVersion = contents.includes( @@ -89,7 +91,7 @@ export default class ModalDownload extends React.Component< includeRowIdAndRowVersion, csvTableDescriptor: { separator }, } - SynapseClient.getDownloadFromTableRequest(downloadFromTableRequest, token) + SynapseClient.getDownloadFromTableRequest(downloadFromTableRequest, this.context.accessToken) .then(data => { this.setState({ isLoading: false, @@ -104,9 +106,8 @@ export default class ModalDownload extends React.Component< onDownload = () => { const { data } = this.state - const { token } = this.props // data will always be defined if calling this function - SynapseClient.getFileHandleByIdURL(data!.resultsFileHandleId, token).then( + SynapseClient.getFileHandleByIdURL(data!.resultsFileHandleId, this.context.accessToken).then( url => { window.location.href = url this.props.onClose() diff --git a/src/lib/containers/QueryCount.tsx b/src/lib/containers/QueryCount.tsx index 17cea6dfee..ebfdbb7e06 100644 --- a/src/lib/containers/QueryCount.tsx +++ b/src/lib/containers/QueryCount.tsx @@ -1,17 +1,17 @@ import { SynapseConstants, SynapseClient } from '../utils/' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { QueryBundleRequest, FacetColumnValuesRequest, } from '../utils/synapseTypes/' import { parseEntityIdFromSqlStatement } from '../utils/functions/sqlFunctions' +import { SynapseContext } from '../utils/SynapseContext' export type QueryCountProps = { sql: string selectedFacets?: FacetColumnValuesRequest[] parens?: boolean name: string - token?: string } const QueryCount: React.FunctionComponent = ({ @@ -19,12 +19,15 @@ const QueryCount: React.FunctionComponent = ({ selectedFacets, parens, name, - token, }) => { + const { accessToken } = useContext(SynapseContext) const [storedSqlQueryCount, setStoredSqlQueryCount] = useState<{}>({}) // maps sql string to true/false, true if already made a request for this sql's query count // false or undefined if not - const [isCalculatingQueryCountForSql, setIsCalculatingQueryCountForSql] = useState<{}>({}) + const [ + isCalculatingQueryCountForSql, + setIsCalculatingQueryCountForSql, + ] = useState<{}>({}) let mounted = true useEffect(() => { @@ -32,14 +35,15 @@ const QueryCount: React.FunctionComponent = ({ if (mounted) { const entityId = parseEntityIdFromSqlStatement(sql) if ( - isCalculatingQueryCountForSql[`${sql}-${token}`] || - storedSqlQueryCount[`${sql}-${token}`] + isCalculatingQueryCountForSql[`${sql}-${accessToken}`] || + storedSqlQueryCount[`${sql}-${accessToken}`] ) { // its either in progress or its already been calculated return } const request: QueryBundleRequest = { - concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest', + concreteType: + 'org.sagebionetworks.repo.model.table.QueryBundleRequest', query: { sql, selectedFacets, @@ -48,15 +52,15 @@ const QueryCount: React.FunctionComponent = ({ partMask: SynapseConstants.BUNDLE_MASK_QUERY_COUNT, } const newIsCalculatingQueryCountForSql = { - ...isCalculatingQueryCountForSql, + ...isCalculatingQueryCountForSql, } - newIsCalculatingQueryCountForSql[`${sql}-${token}`] = true + newIsCalculatingQueryCountForSql[`${sql}-${accessToken}`] = true setIsCalculatingQueryCountForSql(newIsCalculatingQueryCountForSql) - SynapseClient.getQueryTableResults(request, token).then(data => { + SynapseClient.getQueryTableResults(request, accessToken).then(data => { const newStoredSqlQueryCount = { - ...storedSqlQueryCount + ...storedSqlQueryCount, } - newStoredSqlQueryCount[`${sql}-${token}`] = data!.queryCount + newStoredSqlQueryCount[`${sql}-${accessToken}`] = data!.queryCount setStoredSqlQueryCount(newStoredSqlQueryCount) }) } @@ -67,10 +71,9 @@ const QueryCount: React.FunctionComponent = ({ return () => { mounted = false } + }, [sql, selectedFacets, accessToken]) - }, [sql, selectedFacets, token]) - - const count = storedSqlQueryCount[`${sql}-${token}`] + const count = storedSqlQueryCount[`${sql}-${accessToken}`] const localCount = count?.toLocaleString() /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Using_toLocaleString */ return ( @@ -79,4 +82,4 @@ const QueryCount: React.FunctionComponent = ({ ) } -export default QueryCount \ No newline at end of file +export default QueryCount diff --git a/src/lib/containers/QueryWrapper.tsx b/src/lib/containers/QueryWrapper.tsx index 640ab5ea66..963209518a 100644 --- a/src/lib/containers/QueryWrapper.tsx +++ b/src/lib/containers/QueryWrapper.tsx @@ -12,11 +12,11 @@ import { import { cloneDeep } from 'lodash-es' import { SynapseClientError } from '../utils/SynapseClient' import { DEFAULT_PAGE_SIZE } from '../utils/SynapseConstants' +import { SynapseContext } from '../utils/SynapseContext' export type QueryWrapperProps = { visibleColumnCount?: number initQueryRequest: QueryBundleRequest rgbIndex?: number - token?: string facet?: string unitDescription?: string facetAliases?: {} @@ -74,7 +74,7 @@ export type QueryWrapperState = { in SRC won't generate type errors. */ export type LockedFacet = { - facet?: string, + facet?: string value?: string } @@ -88,7 +88,6 @@ export type FacetSelection = { export type QueryWrapperChildProps = { isAllFilterSelectedForFacet?: {} isLoading?: boolean - token?: string entityId?: string isLoadingNewData?: boolean executeQueryRequest?: (param: QueryBundleRequest) => void @@ -112,7 +111,7 @@ export type QueryWrapperChildProps = { topLevelControlsState?: TopLevelControlsState isColumnSelected?: string[] selectedRowIndices?: number[] - error?: SynapseClientError | undefined, + error?: SynapseClientError | undefined lockedFacet?: LockedFacet } export const QUERY_FILTERS_EXPANDED_CSS: string = 'isShowingFacetFilters' @@ -130,6 +129,7 @@ export default class QueryWrapper extends React.Component< QueryWrapperState > { private componentIndex: number + static contextType = SynapseContext constructor(props: QueryWrapperProps) { super(props) this.executeInitialQueryRequest = this.executeInitialQueryRequest.bind(this) @@ -153,7 +153,7 @@ export default class QueryWrapper extends React.Component< isAllFilterSelectedForFacet: {}, loadNowStarted: false, lastQueryRequest: cloneDeep(this.props.initQueryRequest!), - topLevelControlsState : { + topLevelControlsState: { showColumnFilter: true, showFacetFilter: true, showFacetVisualization, @@ -197,9 +197,6 @@ export default class QueryWrapper extends React.Component< const { loadNow = true } = this.props if (loadNow && !this.state.loadNowStarted) { this.executeInitialQueryRequest() - } else if (loadNow && this.props.token !== prevProps.token) { - // if loadNow is true and they've logged in with a token that is not undefined, null, or an empty string when it was before - this.executeQueryRequest(this.getLastQueryRequest()) } else if ( prevProps.initQueryRequest.query.sql !== this.props.initQueryRequest!.query.sql @@ -258,7 +255,7 @@ export default class QueryWrapper extends React.Component< } return SynapseClient.getQueryTableResults( clonedQueryRequest, - this.props.token, + this.context.accessToken, this.updateParentState, ) .then((data: QueryResultBundle) => { @@ -296,7 +293,7 @@ export default class QueryWrapper extends React.Component< await getNextPageOfData( queryRequest, this.state.data!, - this.props.token, + this.context.accessToken, ).then(newState => { this.setState({ ...newState, @@ -325,13 +322,13 @@ export default class QueryWrapper extends React.Component< }) SynapseClient.getQueryTableResults( initQueryRequest, - this.props.token, + this.context.accessToken, this.updateParentState, ) .then((data: QueryResultBundle) => { const hasMoreData = data.queryResult.queryResults.rows.length === - initQueryRequest.query.limit ?? DEFAULT_PAGE_SIZE + initQueryRequest.query.limit ?? DEFAULT_PAGE_SIZE const isAllFilterSelectedForFacet = cloneDeep( this.state.isAllFilterSelectedForFacet, ) @@ -398,14 +395,18 @@ export default class QueryWrapper extends React.Component< * this is to remove the facet from the charts, search and filter. * @return data: QueryResultBundle */ - public removeLockedFacetData (){ + public removeLockedFacetData() { const lockedFacet = this.props.lockedFacet?.facet - if (lockedFacet && this.state.data) { // for details page, return data without the "locked" facet + if (lockedFacet && this.state.data) { + // for details page, return data without the "locked" facet const data = cloneDeep(this.state.data) - const facets = data.facets?.filter( item => item.columnName.toLowerCase() !== lockedFacet.toLowerCase()) + const facets = data.facets?.filter( + item => item.columnName.toLowerCase() !== lockedFacet.toLowerCase(), + ) data.facets = facets return data - } else { // for other pages, just return the data + } else { + // for other pages, just return the data return this.state.data } } diff --git a/src/lib/containers/StatisticsPlot.tsx b/src/lib/containers/StatisticsPlot.tsx index e74b78289a..8c864a2ea8 100644 --- a/src/lib/containers/StatisticsPlot.tsx +++ b/src/lib/containers/StatisticsPlot.tsx @@ -26,7 +26,6 @@ const months = [ export type StatisticsPlotProps = { request: ProjectFilesStatisticsRequest - token?: string title?: string xtitle?: string ytitle?: string diff --git a/src/lib/containers/StyleGuidistComponentWrapper.tsx b/src/lib/containers/StyleGuidistComponentWrapper.tsx index 3b9d85fb49..2ba595de2d 100644 --- a/src/lib/containers/StyleGuidistComponentWrapper.tsx +++ b/src/lib/containers/StyleGuidistComponentWrapper.tsx @@ -1,9 +1,26 @@ -import * as React from 'react'; -import { MemoryRouter } from 'react-router'; -import RenderIfInView from './RenderIfInView'; +import React from 'react' +import { MemoryRouter } from 'react-router' +import { SynapseWrapper } from '../utils/SynapseContext' +import RenderIfInView from './RenderIfInView' +import UniversalCookies from 'universal-cookie' +import { EXPERIMENTAL_MODE_COOKIE } from '../utils/SynapseConstants' +import { DATETIME_UTC_COOKIE_KEY } from '../utils/functions/DateFormatter' +const cookies = new UniversalCookies() -export default class StyleGuidistComponentWrapper extends React.Component { - public render() { - return {this.props.children} - } -} \ No newline at end of file +export const StyleGuidistComponentWrapper: React.FC = props => { + return ( + + + {props.children} + + + ) +} + +export default StyleGuidistComponentWrapper diff --git a/src/lib/containers/SynapseHomepage.tsx b/src/lib/containers/SynapseHomepage.tsx index fc1f8aabef..c516b74929 100644 --- a/src/lib/containers/SynapseHomepage.tsx +++ b/src/lib/containers/SynapseHomepage.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useContext } from 'react' import { Button } from 'react-bootstrap' import RLogo from '../assets/icons/RLogo' import Python from '../assets/icons/Python' @@ -10,16 +10,16 @@ import { BackendDestinationEnum, } from '../utils/functions/getEndpoint' import { SynapsePoweredPortal } from './SynapsePoweredPortal' +import { SynapseContext } from '../utils/SynapseContext' export type SynapseHomepageProps = { - token?: string projectViewId: string } export const SynapseHomepage: React.FunctionComponent = ({ - token, projectViewId, }) => { + const { accessToken } = useContext(SynapseContext) const LOGIN_LINK = `${getEndpoint( BackendDestinationEnum.PORTAL_ENDPOINT, )}#!LoginPlace:0` @@ -62,7 +62,7 @@ export const SynapseHomepage: React.FunctionComponent = ({ alt="" />
- {token ? ( + {accessToken ? ( <>
@@ -176,9 +176,9 @@ export const SynapseHomepage: React.FunctionComponent = ({ @@ -210,9 +210,9 @@ export const SynapseHomepage: React.FunctionComponent = ({ @@ -322,14 +322,47 @@ export const SynapseHomepage: React.FunctionComponent = ({

Powered By Synapse

-

Our knowledge portals are community-specific interfaces that enable researchers to explore and share data, analyses, and tools.

+

+ Our knowledge portals are community-specific interfaces that enable + researchers to explore and share data, analyses, and tools. +

- - - - - - + + + + + +
@@ -436,7 +469,7 @@ export const SynapseHomepage: React.FunctionComponent = ({

Sign up for Synapse today

- {token ? ( + {accessToken ? ( <>
} @@ -484,11 +484,9 @@ const RequestDataAccessStep2: React.FC = props => { id={"duc-download"} variant={"link"} className={"SRC-noPadding"} - token={token} />
} = props => { id={"irb-download"} variant={"link"} className={"SRC-noPadding"} - token={token} /> } = props => { fileName={attachment?.fileName} variant={"link"} className={"SRC-noPadding attachment-download"} - token={token} /> {showDownloadModal && ( setShowDownloadModal(false)} /> diff --git a/src/lib/containers/download_list_v2/AvailableForDownloadTable.md b/src/lib/containers/download_list_v2/AvailableForDownloadTable.md index 9637be6e45..ccd115b8b4 100644 --- a/src/lib/containers/download_list_v2/AvailableForDownloadTable.md +++ b/src/lib/containers/download_list_v2/AvailableForDownloadTable.md @@ -1,3 +1,3 @@ ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/download_list_v2/AvailableForDownloadTable.tsx b/src/lib/containers/download_list_v2/AvailableForDownloadTable.tsx index 93c63a7055..07838aade7 100644 --- a/src/lib/containers/download_list_v2/AvailableForDownloadTable.tsx +++ b/src/lib/containers/download_list_v2/AvailableForDownloadTable.tsx @@ -1,11 +1,13 @@ -import React from 'react' +import React, { useContext } from 'react' import { ErrorBoundary, FallbackProps } from 'react-error-boundary' import { ErrorBanner } from '../ErrorBanner' import * as ReactBootstrap from 'react-bootstrap' import { QueryClient, QueryClientProvider } from 'react-query' import DownloadListTableV2, { DownloadListTableV2Props } from './DownloadListTableV2' +import { SynapseContext } from '../../utils/SynapseContext' export default function AvailableForDownloadTable(props: DownloadListTableV2Props) { + const { accessToken } = useContext(SynapseContext) const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -25,13 +27,13 @@ export default function AvailableForDownloadTable(props: DownloadListTableV2Prop ) } - if (!props.token) { + if (accessToken) { return <> } return ( - + ) diff --git a/src/lib/containers/download_list_v2/DownloadListTableV2.tsx b/src/lib/containers/download_list_v2/DownloadListTableV2.tsx index 65c61c33e9..663728815a 100644 --- a/src/lib/containers/download_list_v2/DownloadListTableV2.tsx +++ b/src/lib/containers/download_list_v2/DownloadListTableV2.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useContext } from 'react' import { useErrorHandler } from 'react-error-boundary' import { DownloadListItemResult } from '../../utils/synapseTypes/DownloadListV2/DownloadListItemResult' import { toError } from '../ErrorBanner' @@ -16,15 +16,16 @@ import UserCard from '../UserCard' import SortIcon from '../../assets/icons/Sort' import { Direction } from '../../utils/synapseTypes' import { SynapseSpinner } from '../LoadingScreen' +import { SynapseContext } from '../../utils/SynapseContext' export type DownloadListTableV2Props = { - token: string } export const TESTING_TRASH_BTN_CLASS = 'TESTING_TRASH_BTN_CLASS' export const TESTING_CLEAR_BTN_CLASS = 'TESTING_CLEAR_BTN_CLASS' export default function DownloadListTableV2(props: DownloadListTableV2Props) { + const { accessToken } = useContext(SynapseContext) const handleError = useErrorHandler() // Load the next page when this ref comes into view. const { ref, inView } = useInView() @@ -38,7 +39,7 @@ export default function DownloadListTableV2(props: DownloadListTableV2Props) { isError, error: newError, refetch - } = useGetAvailableFilesToDownloadInfinite(props.token, sort) + } = useGetAvailableFilesToDownloadInfinite(sort) useEffect(() => { if (isError && newError) { @@ -65,7 +66,7 @@ export default function DownloadListTableV2(props: DownloadListTableV2Props) { const removeItem = async (item: DownloadListItem) => { try { - await SynapseClient.removeItemFromDownloadListV2(item, props.token) + await SynapseClient.removeItemFromDownloadListV2(item, accessToken) refetch() } catch (err) { console.error(err) @@ -155,7 +156,6 @@ export default function DownloadListTableV2(props: DownloadListTableV2Props) { {createdOn} diff --git a/src/lib/containers/entity_finder/EntityFinder.md b/src/lib/containers/entity_finder/EntityFinder.md index cf1d2280c2..e4953d2be3 100644 --- a/src/lib/containers/entity_finder/EntityFinder.md +++ b/src/lib/containers/entity_finder/EntityFinder.md @@ -5,7 +5,6 @@ Regular two-pane Entity Finder with multi-select ```jsx = ({ - accessToken, initialScope, projectId, initialContainer, @@ -100,6 +100,8 @@ export const EntityFinder: React.FunctionComponent = ({ selectedCopy = 'Selected', treeOnly = false, }: EntityFinderProps) => { + const { accessToken } = useContext(SynapseContext) + const [searchActive, setSearchActive] = useState(false) // The raw value of the search input box: const [searchInput, setSearchInput] = useState() @@ -260,6 +262,7 @@ export const EntityFinder: React.FunctionComponent = ({ icon={faSearch} className="SearchIcon" /> + {/* eslint-disable-next-line jsx-a11y/no-redundant-roles */} = ({ {/* We have a separate Details component for search in order to preserve state in the other component between searches */} {searchActive && ( 0 ? { @@ -329,7 +331,6 @@ export const EntityFinder: React.FunctionComponent = ({ {treeOnly ? (
= ({ flex={0.18} > = ({ = ({ {selectedEntities.length > 0 && ( void } export const SelectionPane: React.FC = ({ - accessToken, title, selectedEntities, toggleSelection, @@ -30,7 +28,6 @@ export const SelectionPane: React.FC = ({ }`} > @@ -42,14 +39,12 @@ export const SelectionPane: React.FC = ({ } const EntityPathDisplay: React.FunctionComponent<{ - accessToken: string entity: Reference toggleSelection: (entity: Reference) => void -}> = ({ accessToken, entity, toggleSelection }) => { +}> = ({ entity, toggleSelection }) => { const ENTITY_PATH_TOOLTIP_ID = `EntityPathDisplayReactTooltip_${entity.targetId}` const { data: bundle } = useGetEntityBundle( - accessToken, entity.targetId, BUNDLE_REQUEST_OBJECT, entity.targetVersionNumber, diff --git a/src/lib/containers/entity_finder/details/EntityDetailsList.tsx b/src/lib/containers/entity_finder/details/EntityDetailsList.tsx index 0c2a80f6d9..f5a8d425e9 100644 --- a/src/lib/containers/entity_finder/details/EntityDetailsList.tsx +++ b/src/lib/containers/entity_finder/details/EntityDetailsList.tsx @@ -40,7 +40,6 @@ export type EntityDetailsListDataConfiguration = { * We collect them into this type to simplify passing them through to the view. */ export type EntityDetailsListSharedProps = { - accessToken: string showVersionSelection: boolean selectColumnType: 'checkbox' | 'none' visibleTypes: EntityType[] diff --git a/src/lib/containers/entity_finder/details/configurations/EntityChildrenDetails.tsx b/src/lib/containers/entity_finder/details/configurations/EntityChildrenDetails.tsx index 2b66d8af4e..033008b2d3 100644 --- a/src/lib/containers/entity_finder/details/configurations/EntityChildrenDetails.tsx +++ b/src/lib/containers/entity_finder/details/configurations/EntityChildrenDetails.tsx @@ -11,7 +11,6 @@ type EntityChildrenDetailsProps = EntityDetailsListSharedProps & { } export const EntityChildrenDetails: React.FunctionComponent = ({ - accessToken, parentContainerId, visibleTypes: includeTypes, showVersionSelection, @@ -32,7 +31,7 @@ export const EntityChildrenDetails: React.FunctionComponent + /> ) } diff --git a/src/lib/containers/entity_finder/details/configurations/FavoritesDetails.tsx b/src/lib/containers/entity_finder/details/configurations/FavoritesDetails.tsx index 1e25b2400a..fb299d61ab 100644 --- a/src/lib/containers/entity_finder/details/configurations/FavoritesDetails.tsx +++ b/src/lib/containers/entity_finder/details/configurations/FavoritesDetails.tsx @@ -8,7 +8,6 @@ import { DetailsView } from '../view/DetailsView' type FavoritesDetailsProps = EntityDetailsListSharedProps export const FavoritesDetails: React.FunctionComponent = ({ - accessToken, showVersionSelection, selectColumnType, selected, @@ -16,9 +15,7 @@ export const FavoritesDetails: React.FunctionComponent = selectableTypes, toggleSelection, }) => { - const { data, status, isFetching, isError, error } = useGetFavorites( - accessToken, - ) + const { data, status, isFetching, isError, error } = useGetFavorites() const handleError = useErrorHandler() useEffect(() => { @@ -29,7 +26,6 @@ export const FavoritesDetails: React.FunctionComponent = return ( = visibleTypes={includeTypes} selectableTypes={selectableTypes} toggleSelection={toggleSelection} - > + /> ) } diff --git a/src/lib/containers/entity_finder/details/configurations/ProjectListDetails.tsx b/src/lib/containers/entity_finder/details/configurations/ProjectListDetails.tsx index 4cf9c90dad..a2a4887a1e 100644 --- a/src/lib/containers/entity_finder/details/configurations/ProjectListDetails.tsx +++ b/src/lib/containers/entity_finder/details/configurations/ProjectListDetails.tsx @@ -12,7 +12,6 @@ type ProjectListDetailsProps = EntityDetailsListSharedProps & { } export const ProjectListDetails: React.FunctionComponent = ({ - accessToken, projectsParams, showVersionSelection, selectColumnType, @@ -29,7 +28,7 @@ export const ProjectListDetails: React.FunctionComponent { @@ -40,7 +39,6 @@ export const ProjectListDetails: React.FunctionComponent + /> ) } diff --git a/src/lib/containers/entity_finder/details/configurations/SearchDetails.tsx b/src/lib/containers/entity_finder/details/configurations/SearchDetails.tsx index b03e0d9ff2..47898e44ca 100644 --- a/src/lib/containers/entity_finder/details/configurations/SearchDetails.tsx +++ b/src/lib/containers/entity_finder/details/configurations/SearchDetails.tsx @@ -11,7 +11,6 @@ type SearchDetailsProps = EntityDetailsListSharedProps & { } export const SearchDetails: React.FunctionComponent = ({ - accessToken, searchQuery, showVersionSelection, selectColumnType, @@ -28,7 +27,7 @@ export const SearchDetails: React.FunctionComponent = ({ fetchNextPage, error, isError, - } = useSearchInfinite(searchQuery, accessToken, { + } = useSearchInfinite(searchQuery, { enabled: !!searchQuery.queryTerm, }) const handleError = useErrorHandler() @@ -42,7 +41,6 @@ export const SearchDetails: React.FunctionComponent = ({ if (searchQuery.queryTerm) { return ( = ({

} - >
+ /> ) } else { return ( = ({

Enter a term or Synapse ID to start searching

} - >
+ /> ) } } diff --git a/src/lib/containers/entity_finder/details/view/DetailsView.tsx b/src/lib/containers/entity_finder/details/view/DetailsView.tsx index 71891e5191..6a2ad4eb64 100644 --- a/src/lib/containers/entity_finder/details/view/DetailsView.tsx +++ b/src/lib/containers/entity_finder/details/view/DetailsView.tsx @@ -43,7 +43,6 @@ export const DetailsView: React.FunctionComponent = ({ queryIsFetching, hasNextPage, fetchNextPage, - accessToken, showVersionSelection, selectColumnType, selected, @@ -168,7 +167,6 @@ export const DetailsView: React.FunctionComponent = ({ return ( = ({ - accessToken, entityHeader, appearance, showVersionColumn, @@ -51,6 +50,7 @@ export const DetailsViewRow: React.FunctionComponent = ({ selectedVersion, toggleSelection, }) => { + const { accessToken } = useContext(SynapseContext) const isSelected = appearance === 'selected' const isDisabled = appearance === 'disabled' const isHidden = appearance === 'hidden' @@ -70,7 +70,6 @@ export const DetailsViewRow: React.FunctionComponent = ({ ) const { data: bundle, isError, error } = useGetEntityBundle( - accessToken, entityHeader.id, BUNDLE_REQUEST_OBJECT, undefined, @@ -84,7 +83,6 @@ export const DetailsViewRow: React.FunctionComponent = ({ const { data: modifiedByUserProfile } = useGetUserProfileWithProfilePic( bundle?.entity?.modifiedBy ?? '273950', - accessToken, { enabled: !!bundle, staleTime: 60 * 1000, // 60 seconds @@ -99,7 +97,7 @@ export const DetailsViewRow: React.FunctionComponent = ({ useEffect(() => { if (isSelected && versions === undefined) { - SynapseClient.getEntityVersions(accessToken, entityHeader.id).then( + SynapseClient.getEntityVersions(entityHeader.id, accessToken).then( response => { setVersions(response.results) }, diff --git a/src/lib/containers/entity_finder/tree/TreeNode.tsx b/src/lib/containers/entity_finder/tree/TreeNode.tsx index e80aff66d5..af30fced7f 100644 --- a/src/lib/containers/entity_finder/tree/TreeNode.tsx +++ b/src/lib/containers/entity_finder/tree/TreeNode.tsx @@ -28,7 +28,6 @@ export enum NodeAppearance { } export type TreeNodeProps = { - accessToken: string entityHeader?: EntityHeader | ProjectHeader selected: Reference[] setSelectedId: (entityId: string) => void @@ -42,7 +41,6 @@ export type TreeNodeProps = { } export const TreeNode: React.FunctionComponent = ({ - accessToken, entityHeader, selected, setSelectedId, @@ -88,7 +86,6 @@ export const TreeNode: React.FunctionComponent = ({ hasNextPage, isSuccess, } = useGetEntityChildrenInfinite( - accessToken, { parentId: nodeId, includeTypes: visibleTypes, @@ -102,7 +99,6 @@ export const TreeNode: React.FunctionComponent = ({ ) const { data: bundle } = useGetEntityBundle( - accessToken, nodeId, BUNDLE_REQUEST_OBJECT, undefined, @@ -200,7 +196,6 @@ export const TreeNode: React.FunctionComponent = ({ return ( = ({ {showScopeAsRootNode ? ( = ({ = ({ userId, date, - accessToken, utc, }) => { return ( @@ -30,11 +28,7 @@ export const CreatedOnByUserDiv: React.FunctionComponent - +
) } diff --git a/src/lib/containers/evaluation_queues/EvaluationCard.md b/src/lib/containers/evaluation_queues/EvaluationCard.md index 89caf45af0..cd3b3025b1 100644 --- a/src/lib/containers/evaluation_queues/EvaluationCard.md +++ b/src/lib/containers/evaluation_queues/EvaluationCard.md @@ -12,7 +12,6 @@ }} alert("Edit clicked")} onModifyAccess={() => alert("Modify Access clicked")} diff --git a/src/lib/containers/evaluation_queues/EvaluationCard.tsx b/src/lib/containers/evaluation_queues/EvaluationCard.tsx index 4fa1430462..c7a5df5878 100644 --- a/src/lib/containers/evaluation_queues/EvaluationCard.tsx +++ b/src/lib/containers/evaluation_queues/EvaluationCard.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { deleteEvaluation, getEvaluationPermissions, @@ -13,6 +13,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { UserEvaluationPermissions } from '../../utils/synapseTypes/Evaluation/UserEvaluationPermissions' import { RequiredProperties } from '../../utils' import WarningModal from '../synapse_form_wrapper/WarningModal' +import { SynapseContext } from '../../utils/SynapseContext' export type ExistingEvaluation = RequiredProperties< Evaluation, @@ -22,8 +23,6 @@ export type ExistingEvaluation = RequiredProperties< export type EvaluationCardProps = { /** properties of the Evaluation to show*/ evaluation: ExistingEvaluation - /** access token to make authenticated API calls */ - accessToken: string /** If true, dates for start/end are displayed in UTC instead of local time*/ utc: boolean /** Callback when the Edit option in the dropdown is clicked*/ @@ -47,13 +46,13 @@ export type EvaluationCardProps = { */ export const EvaluationCard: React.FunctionComponent = ({ evaluation, - accessToken, utc, onEdit, onModifyAccess, onSubmit, onDeleteSuccess, }: EvaluationCardProps) => { + const { accessToken } = useContext(SynapseContext) const [error, setError] = useState() const [permissions, setPermissions] = useState() @@ -108,7 +107,6 @@ export const EvaluationCard: React.FunctionComponent = ({ {permissions?.canSubmit && ( diff --git a/src/lib/containers/evaluation_queues/EvaluationEditor.tsx b/src/lib/containers/evaluation_queues/EvaluationEditor.tsx index 9dacd4d2de..ab29b9f0e1 100644 --- a/src/lib/containers/evaluation_queues/EvaluationEditor.tsx +++ b/src/lib/containers/evaluation_queues/EvaluationEditor.tsx @@ -1,5 +1,5 @@ import { Alert, Button, Col, Dropdown, Form, Row } from 'react-bootstrap' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { createEvaluation, deleteEvaluation, @@ -13,10 +13,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' import { CreatedOnByUserDiv } from './CreatedOnByUserDiv' import WarningModal from '../synapse_form_wrapper/WarningModal' +import { SynapseContext } from '../../utils/SynapseContext' export type EvaluationEditorProps = { - /** access token to make authenticated API calls */ - readonly accessToken: string /** Use if UPDATING an existing Evaluation. Id of the evaluation to edit */ readonly evaluationId?: string /** Use if CREATING a new Evaluation. Id of the Entity that will be associated with the Evaluation */ @@ -33,7 +32,6 @@ export type EvaluationEditorProps = { * Edits basic properties of an Evaluation */ export const EvaluationEditor: React.FunctionComponent = ({ - accessToken, evaluationId, entityId, utc, @@ -43,7 +41,7 @@ export const EvaluationEditor: React.FunctionComponent = if (evaluationId && entityId) { throw new Error('please use either evaluationId or entityId but not both') } - + const { accessToken } = useContext(SynapseContext) const [error, setError] = useState() const [showSaveSuccess, setShowSaveSuccess] = useState(false) @@ -182,11 +180,10 @@ export const EvaluationEditor: React.FunctionComponent = )} - {error && } + {error && } {showSaveSuccess && ( + ``` ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/evaluation_queues/EvaluationEditorPage.tsx b/src/lib/containers/evaluation_queues/EvaluationEditorPage.tsx index 748322679e..39a59ce436 100644 --- a/src/lib/containers/evaluation_queues/EvaluationEditorPage.tsx +++ b/src/lib/containers/evaluation_queues/EvaluationEditorPage.tsx @@ -4,8 +4,6 @@ import { EvaluationRoundEditorList } from './EvaluationRoundEditorList' import { Alert, Button } from 'react-bootstrap' export type EvaluationEditorPageProps = { - /** access token to make authenticated API calls */ - readonly accessToken: string /** Use if UPDATING an existing Evaluation. Id of the evaluation to edit */ readonly evaluationId?: string /** Use if CREATING a new Evaluation. Id of the Entity that will be associated with the Evaluation */ @@ -20,7 +18,6 @@ export type EvaluationEditorPageProps = { * Combined editor that allows editing an Evaluation's data and also it's associated rounds (once the Evaluation exists on Synapse) */ export const EvaluationEditorPage: React.FunctionComponent = ({ - accessToken, evaluationId, entityId, utc, @@ -32,7 +29,6 @@ export const EvaluationEditorPage: React.FunctionComponent {savedEvaluationId ? ( diff --git a/src/lib/containers/evaluation_queues/EvaluationRoundEditor.tsx b/src/lib/containers/evaluation_queues/EvaluationRoundEditor.tsx index 1ad213e78c..1c47b93fe1 100644 --- a/src/lib/containers/evaluation_queues/EvaluationRoundEditor.tsx +++ b/src/lib/containers/evaluation_queues/EvaluationRoundEditor.tsx @@ -1,5 +1,5 @@ import { EvaluationRound, EvaluationRoundLimit } from '../../utils/synapseTypes' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { Alert, Button, @@ -30,9 +30,9 @@ import { import { EvaluationRoundEditorDropdown } from './EvaluationRoundEditorDropdown' import { ErrorBanner } from '../ErrorBanner' import { IconDefinition } from '@fortawesome/fontawesome-svg-core' +import { SynapseContext } from '../../utils/SynapseContext' export type EvaluationRoundEditorProps = { - accessToken: string evaluationRoundInput: EvaluationRoundInput //If true, dates for start/end are displayed in UTC instead of local time utc: boolean @@ -123,12 +123,12 @@ const convertInputsToEvaluationRound = ( } export const EvaluationRoundEditor: React.FunctionComponent = ({ - accessToken, evaluationRoundInput, onSave, onDelete, utc, }) => { + const { accessToken } = useContext(SynapseContext) const [error, setError] = useState() const [showSaveSuccess, setShowSaveSuccess] = useState(false) @@ -335,7 +335,7 @@ export const EvaluationRoundEditor: React.FunctionComponent - + )} diff --git a/src/lib/containers/evaluation_queues/EvaluationRoundEditorList.tsx b/src/lib/containers/evaluation_queues/EvaluationRoundEditorList.tsx index f68e45e692..b25446bd04 100644 --- a/src/lib/containers/evaluation_queues/EvaluationRoundEditorList.tsx +++ b/src/lib/containers/evaluation_queues/EvaluationRoundEditorList.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { useListState } from '../../utils/hooks/useListState' import { EvaluationRoundEditor } from './EvaluationRoundEditor' import { Button } from 'react-bootstrap' @@ -13,10 +13,9 @@ import { import shortid from 'shortid' import { EvaluationRoundListResponse } from '../../utils/synapseTypes/Evaluation/EvaluationRoundListResponse' import { ErrorBanner } from '../ErrorBanner' +import { SynapseContext } from '../../utils/SynapseContext' export type EvaluationRoundEditorListProps = { - /** access token to make authenticated API calls */ - accessToken: string /** id of the Evaluation containing EvaluationRounds to edit*/ evaluationId: string /** If true, dates for start/end are displayed in UTC instead of local time*/ @@ -65,10 +64,10 @@ const fetchEvaluationList = ( * Edits EvaluationsRounds for an Evaluation. */ export const EvaluationRoundEditorList: React.FunctionComponent = ({ - accessToken, evaluationId, utc, }: EvaluationRoundEditorListProps) => { + const { accessToken } = useContext(SynapseContext) const [error, setError] = useState() const { @@ -84,7 +83,7 @@ export const EvaluationRoundEditorList: React.FunctionComponent { fetchEvaluationList( evaluationId, - accessToken, + accessToken!, setEvaluationRoundInputList, setError, ) @@ -96,7 +95,7 @@ export const EvaluationRoundEditorList: React.FunctionComponent + return } return ( @@ -105,7 +104,6 @@ export const EvaluationRoundEditorList: React.FunctionComponent { return ( = ({ data, isLoading, facetAliases, - token, }: FacetPlotsCardProps): JSX.Element => { + const { accessToken } = useContext(SynapseContext) const [facetPlotDataArray, setFacetPlotDataArray] = useState([]) const [facetDataArray, setFacetDataArray] = useState([]) const [selectedFacetValue, setSelectedFacetValue] = useState('') @@ -87,7 +88,7 @@ const FacetPlotsCard: React.FunctionComponent = ({ getColumnType(item), index + 1, //individual plot rgbIndex 'PIE', - token, + accessToken, ) return plotData }), diff --git a/src/lib/containers/home_page/featured-data/FeaturedDataPlots.tsx b/src/lib/containers/home_page/featured-data/FeaturedDataPlots.tsx index 3cb9ed81ad..7c0fb8ec62 100644 --- a/src/lib/containers/home_page/featured-data/FeaturedDataPlots.tsx +++ b/src/lib/containers/home_page/featured-data/FeaturedDataPlots.tsx @@ -5,7 +5,6 @@ import SingleQueryFacetPlotsCards, { SingleQueryFacetPlotsCardsProps } from './S export type QueryFacetPlotsCardsProps = QueryPerFacetPlotsCardProps | SingleQueryFacetPlotsCardsProps export type FeaturedDataPlotsProps = { - token?: string configs: QueryFacetPlotsCardsProps[] rgbIndex?: number sql?: string, @@ -17,7 +16,6 @@ const FeaturedDataPlots: React.FunctionComponent = props configs, rgbIndex, sql, - token, } = props // What mode are we in? Either every card has a different selected facet (requiring a different query), // or we're showing the facet counts for a single query. This controls the layout, and how the cards are populated. @@ -30,15 +28,13 @@ const FeaturedDataPlots: React.FunctionComponent = props + sql={sql} /> } {!isQueryPerCard && + sql={sql} /> } })} diff --git a/src/lib/containers/home_page/featured-data/FeaturedDataTabs.tsx b/src/lib/containers/home_page/featured-data/FeaturedDataTabs.tsx index 8a29aacfe4..9033943c7a 100644 --- a/src/lib/containers/home_page/featured-data/FeaturedDataTabs.tsx +++ b/src/lib/containers/home_page/featured-data/FeaturedDataTabs.tsx @@ -13,7 +13,6 @@ export type FeatureDataTabProps = { } export type FeaturedDataTabsProps = { - token?: string configs: FeatureDataTabProps[] rgbIndex: number sql: string @@ -21,7 +20,7 @@ export type FeaturedDataTabsProps = { const FeaturedDataTabs: React.FunctionComponent = props => { const [selectedTabIndex, setSelectedTabIndex] = useState(0) - const { configs, rgbIndex, sql, token } = props + const { configs, rgbIndex, sql } = props // explore all data button const selectedTabProps: FeatureDataTabProps = configs[selectedTabIndex] return ( @@ -56,7 +55,6 @@ const FeaturedDataTabs: React.FunctionComponent = props = rgbIndex={rgbIndex} sql={sql} explorePagePath={selectedTabProps.explorePagePath} - token={token} /> {selectedTabProps.explorePagePath && (
diff --git a/src/lib/containers/home_page/featured-data/QueryPerFacetPlotsCard.tsx b/src/lib/containers/home_page/featured-data/QueryPerFacetPlotsCard.tsx index 56d93d6099..9689cb8e73 100644 --- a/src/lib/containers/home_page/featured-data/QueryPerFacetPlotsCard.tsx +++ b/src/lib/containers/home_page/featured-data/QueryPerFacetPlotsCard.tsx @@ -7,7 +7,6 @@ import { ErrorBanner } from '../../ErrorBanner' import FacetPlotsCard from './FacetPlotsCard' export type QueryPerFacetPlotsCardProps = { - token?: string title?: string description?: string rgbIndex?: number @@ -57,7 +56,6 @@ const QueryPerFacetPlotsCard: React.FunctionComponent - + = props => { - const { sql, facetsToPlot, rgbIndex, token, ...rest } = props + const { sql, facetsToPlot, rgbIndex, ...rest } = props const initQueryRequest: QueryBundleRequest = getQueryRequest(sql!) return (
- + {facetsToPlot?.map(facetName => { return ( - + ) })} diff --git a/src/lib/containers/home_page/goals/Goals.Desktop.tsx b/src/lib/containers/home_page/goals/Goals.Desktop.tsx index b01bda29e1..6c19aff531 100644 --- a/src/lib/containers/home_page/goals/Goals.Desktop.tsx +++ b/src/lib/containers/home_page/goals/Goals.Desktop.tsx @@ -9,7 +9,6 @@ export default function GoalsDesktop({ summary, countSql, title, - token, }: GoalsDataProps) { return (
@@ -21,7 +20,7 @@ export default function GoalsDesktop({ {title} {countSql && ( - + )}

diff --git a/src/lib/containers/home_page/goals/Goals.Mobile.tsx b/src/lib/containers/home_page/goals/Goals.Mobile.tsx index 3de480961a..c719b6fecc 100644 --- a/src/lib/containers/home_page/goals/Goals.Mobile.tsx +++ b/src/lib/containers/home_page/goals/Goals.Mobile.tsx @@ -9,13 +9,12 @@ export default function GoalsMobile({ summary, countSql, title, - token, }: GoalsDataProps) { const titleElement = (
{countSql && ( - + )} {title} diff --git a/src/lib/containers/home_page/goals/Goals.md b/src/lib/containers/home_page/goals/Goals.md index 8aac1ff265..b1b5765da6 100644 --- a/src/lib/containers/home_page/goals/Goals.md +++ b/src/lib/containers/home_page/goals/Goals.md @@ -1,3 +1,3 @@ ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/home_page/goals/Goals.tsx b/src/lib/containers/home_page/goals/Goals.tsx index d6fd9622ca..69ebcc39ad 100644 --- a/src/lib/containers/home_page/goals/Goals.tsx +++ b/src/lib/containers/home_page/goals/Goals.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { QueryBundleRequest, FileHandleAssociation, @@ -14,10 +14,10 @@ import GoalsMobile from './Goals.Mobile' import GoalsDesktop from './Goals.Desktop' import { getFieldIndex } from '../../../utils/functions/queryUtils' import { withQueryClientProvider } from '../../../utils/hooks/SynapseAPI/QueryClientProviderWrapper' +import { SynapseContext } from '../../../utils/SynapseContext' export type GoalsProps = { entityId: string - token?: string } export type GoalsDataProps = { @@ -26,7 +26,6 @@ export type GoalsDataProps = { summary: string link: string asset: string - token?: string } enum ExpectedColumns { @@ -40,7 +39,8 @@ enum ExpectedColumns { export const Goals: React.FC = withQueryClientProvider( (props: GoalsProps) => { - const { entityId, token } = props + const { entityId } = props + const { accessToken } = useContext(SynapseContext) const [assets, setAssets] = useState() const [error, setError] = useState< string | SynapseClientError | undefined @@ -58,7 +58,6 @@ export const Goals: React.FC = withQueryClientProvider( } const { data: queryResultBundle } = useGetQueryResultBundle( queryBundleRequest, - token, ) useEffect(() => { @@ -91,7 +90,7 @@ export const Goals: React.FC = withQueryClientProvider( includePreviewPreSignedURLs: false, requestedFiles: fileHandleAssociationList, } - const files = await getFiles(batchFileRequest, token) + const files = await getFiles(batchFileRequest, accessToken) setError(undefined) setAssets( files.requestedFiles @@ -104,7 +103,7 @@ export const Goals: React.FC = withQueryClientProvider( } } getData() - }, [entityId, token, queryResultBundle]) + }, [entityId, accessToken, queryResultBundle]) const tableIdColumnIndex = getFieldIndex( ExpectedColumns.TABLEID, @@ -130,7 +129,7 @@ export const Goals: React.FC = withQueryClientProvider( return (
- {error && } + {error && } {queryResultBundle?.queryResult.queryResults.rows.map((el, index) => { const values = el.values const tableId = @@ -153,7 +152,6 @@ export const Goals: React.FC = withQueryClientProvider( summary, link, asset, - token, } return showDesktop ? ( diff --git a/src/lib/containers/home_page/people/UserCardListGroups.tsx b/src/lib/containers/home_page/people/UserCardListGroups.tsx index 22ab117873..6604110682 100644 --- a/src/lib/containers/home_page/people/UserCardListGroups.tsx +++ b/src/lib/containers/home_page/people/UserCardListGroups.tsx @@ -14,7 +14,6 @@ export type UserCardListGroupsProps = { summaryLinkText?: string count: number useQueryResultUserData?: boolean - token?: string } export default function UserCardListGroups(props: UserCardListGroupsProps) { diff --git a/src/lib/containers/home_page/programs/Programs.md b/src/lib/containers/home_page/programs/Programs.md index a5ec71efcf..9c53efb389 100644 --- a/src/lib/containers/home_page/programs/Programs.md +++ b/src/lib/containers/home_page/programs/Programs.md @@ -13,6 +13,5 @@ URLColumnName: 'Program', matchColumnName: 'Program', }} - token={accessToken} /> ``` \ No newline at end of file diff --git a/src/lib/containers/home_page/programs/Programs.tsx b/src/lib/containers/home_page/programs/Programs.tsx index e52399df62..b94719a126 100644 --- a/src/lib/containers/home_page/programs/Programs.tsx +++ b/src/lib/containers/home_page/programs/Programs.tsx @@ -21,7 +21,6 @@ export type ProgramsProps = { iconColumnName: string linkConfig: CardLink iconOptions: IconOptions - token?: string } export type ProgramsDataProps = { @@ -43,7 +42,6 @@ export const Programs: React.FC = withQueryClientProvider( summaryColumnName, iconColumnName, linkConfig, - token, rgbIndex, iconOptions, } = props @@ -61,7 +59,6 @@ export const Programs: React.FC = withQueryClientProvider( } const { data: queryResultBundle } = useGetQueryResultBundle( queryBundleRequest, - token, ) const titleColumnIndex = getFieldIndex(titleColumnName, queryResultBundle) diff --git a/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.md b/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.md index 607a750771..ac19dbaa8c 100644 --- a/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.md +++ b/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.md @@ -2,7 +2,6 @@ ```jsx
diff --git a/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.tsx b/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.tsx index 600ef873f1..ac7545198e 100644 --- a/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.tsx +++ b/src/lib/containers/home_page/project_view_carousel/ProjectViewCarousel.tsx @@ -2,14 +2,14 @@ import { SynapseClient, SynapseConstants } from '../../../utils' import { getFieldIndex } from '../../../utils/functions/queryUtils' import useGetQueryResultBundle from '../../../utils/hooks/SynapseAPI/useGetQueryResultBundle' import { QueryBundleRequest } from '../../../utils/synapseTypes' -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useContext } from 'react' import Carousel from '../../Carousel' import { ProjectViewCard } from './ProjectViewCard' import { ErrorBanner } from '../../ErrorBanner' import { withQueryClientProvider } from '../../../utils/hooks/SynapseAPI/QueryClientProviderWrapper' +import { SynapseContext } from '../../../utils/SynapseContext' export type ProjectViewCarouselProps = { - token?: string entityId: string } @@ -35,7 +35,7 @@ enum ExpectedColumns { * be an attachment on the project's root wiki page. */ export const ProjectViewCarousel: React.FunctionComponent = withQueryClientProvider( - ({ token, entityId }) => { + ({ entityId }) => { const queryBundleRequest: QueryBundleRequest = { concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest', entityId, @@ -47,13 +47,14 @@ export const ProjectViewCarousel: React.FunctionComponent([]) const [error, setError] = useState() const { data: queryResultBundle, error: queryError, isLoading, - } = useGetQueryResultBundle(queryBundleRequest, token) + } = useGetQueryResultBundle(queryBundleRequest) useEffect(() => { const getData = async () => { @@ -102,12 +103,12 @@ export const ProjectViewCarousel: React.FunctionComponent
diff --git a/src/lib/containers/home_page/resources/Resources.Desktop.tsx b/src/lib/containers/home_page/resources/Resources.Desktop.tsx index 0e994773c4..261733cd9b 100644 --- a/src/lib/containers/home_page/resources/Resources.Desktop.tsx +++ b/src/lib/containers/home_page/resources/Resources.Desktop.tsx @@ -4,13 +4,9 @@ import MarkdownSynapse from '../../MarkdownSynapse' export type ResourcesDesktopProps = { data: Data - token?: string } -export default function ResourcesDesktop({ - data, - token, -}: ResourcesDesktopProps) { +export default function ResourcesDesktop({ data }: ResourcesDesktopProps) { const [index, setIndex] = useState(0) return (
@@ -37,11 +33,7 @@ export default function ResourcesDesktop({ const { ownerId, wikiId } = el return ( - + ) })} diff --git a/src/lib/containers/home_page/resources/Resources.Mobile.tsx b/src/lib/containers/home_page/resources/Resources.Mobile.tsx index 57214f866b..73f84543e0 100644 --- a/src/lib/containers/home_page/resources/Resources.Mobile.tsx +++ b/src/lib/containers/home_page/resources/Resources.Mobile.tsx @@ -5,16 +5,15 @@ import ExpandableContent from '../ExpandableContent' export type ResourcesMobileProps = { data: Data - token?: string } -export default function ResourcesMobile({ data, token }: ResourcesMobileProps) { +export default function ResourcesMobile({ data }: ResourcesMobileProps) { return (
{data.map(({ name, ownerId, wikiId }) => { let title = <> {name} let markdown = ( - + ) return })} diff --git a/src/lib/containers/home_page/resources/Resources.md b/src/lib/containers/home_page/resources/Resources.md index 6456df80ec..375cd06526 100644 --- a/src/lib/containers/home_page/resources/Resources.md +++ b/src/lib/containers/home_page/resources/Resources.md @@ -1,3 +1,3 @@ ```jsx - + ``` \ No newline at end of file diff --git a/src/lib/containers/home_page/resources/Resources.tsx b/src/lib/containers/home_page/resources/Resources.tsx index 1e6f967d01..e9dd795504 100644 --- a/src/lib/containers/home_page/resources/Resources.tsx +++ b/src/lib/containers/home_page/resources/Resources.tsx @@ -11,7 +11,6 @@ import { withQueryClientProvider } from '../../../utils/hooks/SynapseAPI/QueryCl export type ResourcesProps = { entityId: string - token?: string } enum ExpectedColumns { @@ -27,7 +26,7 @@ export type Data = { export const Resources: React.FC = withQueryClientProvider( (props: ResourcesProps) => { - const { entityId, token } = props + const { entityId } = props const showDesktop = useShowDesktop() const queryBundleRequest: QueryBundleRequest = { @@ -42,7 +41,6 @@ export const Resources: React.FC = withQueryClientProvider( } const { data: queryResultBundle, error } = useGetQueryResultBundle( queryBundleRequest, - token, ) const nameIndex = getFieldIndex(ExpectedColumns.NAME, queryResultBundle) @@ -63,11 +61,11 @@ export const Resources: React.FC = withQueryClientProvider( }) ?? [] return (
- + {showDesktop ? ( - + ) : ( - + )}
) diff --git a/src/lib/containers/personal_access_token/AccessTokenCard.tsx b/src/lib/containers/personal_access_token/AccessTokenCard.tsx index 694d52fc6c..44ed45981f 100644 --- a/src/lib/containers/personal_access_token/AccessTokenCard.tsx +++ b/src/lib/containers/personal_access_token/AccessTokenCard.tsx @@ -4,26 +4,27 @@ import { } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import moment from 'moment' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { Button } from 'react-bootstrap' import { useErrorHandler } from 'react-error-boundary' import ReactTooltip from 'react-tooltip' import { SynapseClient } from '../../utils/' +import { SynapseContext } from '../../utils/SynapseContext' import { AccessTokenRecord } from '../../utils/synapseTypes/AccessToken/AccessTokenRecord' import { scopeDescriptions } from '../../utils/synapseTypes/AccessToken/ScopeDescriptions' import WarningModal from '../synapse_form_wrapper/WarningModal' export type AccessTokenCardProps = { + /** Record referring to an access token, not a token itself */ accessToken: AccessTokenRecord - token?: string onDelete: (...args: any[]) => void } export const AccessTokenCard: React.FunctionComponent = ({ accessToken, - token, onDelete, }: AccessTokenCardProps) => { + const { accessToken: authToken } = useContext(SynapseContext) const [showModal, setShowModal] = useState(false) const handleError = useErrorHandler() @@ -58,7 +59,7 @@ export const AccessTokenCard: React.FunctionComponent = ({ confirmButtonText={'Delete Token'} onCancel={() => setShowModal(false)} onConfirm={(id: string) => { - SynapseClient.deletePersonalAccessToken(id, token) + SynapseClient.deletePersonalAccessToken(id, authToken) .then(() => { onDelete() setShowModal(false) @@ -69,7 +70,7 @@ export const AccessTokenCard: React.FunctionComponent = ({ }} confirmButtonVariant="danger" show={showModal} - onConfirmCallbackArgs={[accessToken.id, token]} + onConfirmCallbackArgs={[accessToken.id, authToken]} >
@@ -117,7 +118,7 @@ export const AccessTokenCard: React.FunctionComponent = ({ onClick={() => { if (isExpired) { // token no longer works, no need for warning/confirmation - SynapseClient.deletePersonalAccessToken(accessToken.id, token) + SynapseClient.deletePersonalAccessToken(accessToken.id, authToken) .then(() => { onDelete() }) diff --git a/src/lib/containers/personal_access_token/AccessTokenPage.md b/src/lib/containers/personal_access_token/AccessTokenPage.md index 2d78234917..7d34f91ab3 100644 --- a/src/lib/containers/personal_access_token/AccessTokenPage.md +++ b/src/lib/containers/personal_access_token/AccessTokenPage.md @@ -2,6 +2,5 @@ accessToken && ``` \ No newline at end of file diff --git a/src/lib/containers/personal_access_token/AccessTokenPage.tsx b/src/lib/containers/personal_access_token/AccessTokenPage.tsx index a0853fde46..d0c66cf781 100644 --- a/src/lib/containers/personal_access_token/AccessTokenPage.tsx +++ b/src/lib/containers/personal_access_token/AccessTokenPage.tsx @@ -1,8 +1,9 @@ -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' import { Button } from 'react-bootstrap' import { ErrorBoundary, FallbackProps } from 'react-error-boundary' import { SynapseClient } from '../../utils' import { useListState } from '../../utils/hooks/useListState' +import { SynapseContext } from '../../utils/SynapseContext' import { AccessTokenRecord } from '../../utils/synapseTypes/AccessToken/AccessTokenRecord' import { ErrorBanner } from '../ErrorBanner' import loadingScreen from '../LoadingScreen' @@ -24,14 +25,13 @@ const ErrorFallback: React.FunctionComponent = ({ export type AccessTokenPageProps = { title: string body: string | JSX.Element - token: string } export const AccessTokenPage: React.FunctionComponent = ({ title, body, - token, }: AccessTokenPageProps) => { + const { accessToken } = useContext(SynapseContext) const [isLoading, setIsLoading] = useState(false) const [showCreateTokenModal, setShowCreateTokenModal] = useState(false) @@ -61,7 +61,7 @@ export const AccessTokenPage: React.FunctionComponent = ({ if (loadNextPage) { setLoadNextPage(false) setIsLoading(true) - SynapseClient.getPersonalAccessTokenRecords(token, nextPageToken) + SynapseClient.getPersonalAccessTokenRecords(accessToken, nextPageToken) .then(response => { setIsLoading(false) appendTokenRecords(...response.results) @@ -77,7 +77,7 @@ export const AccessTokenPage: React.FunctionComponent = ({ setShowErrorMessage(true) }) } - }, [loadNextPage, token, nextPageToken]) + }, [loadNextPage, accessToken, nextPageToken]) return (
@@ -98,7 +98,6 @@ export const AccessTokenPage: React.FunctionComponent = ({ {showCreateTokenModal && ( setShowCreateTokenModal(false)} onCreate={rerenderList} > @@ -116,7 +115,6 @@ export const AccessTokenPage: React.FunctionComponent = ({ ) diff --git a/src/lib/containers/personal_access_token/CreateAccessTokenModal.tsx b/src/lib/containers/personal_access_token/CreateAccessTokenModal.tsx index b02200021c..5a231107bd 100644 --- a/src/lib/containers/personal_access_token/CreateAccessTokenModal.tsx +++ b/src/lib/containers/personal_access_token/CreateAccessTokenModal.tsx @@ -8,6 +8,7 @@ import { ModalBody, } from 'react-bootstrap' import { SynapseClient } from '../../utils' +import { SynapseContext } from '../../utils/SynapseContext' import { AccessTokenGenerationRequest } from '../../utils/synapseTypes/AccessToken/AccessTokenGenerationRequest' import { scopeDescriptions } from '../../utils/synapseTypes/AccessToken/ScopeDescriptions' import { CopyToClipboardInput } from '../CopyToClipboardInput' @@ -21,14 +22,13 @@ const INVALID_INPUT_MSG = export type CreateAccessTokenModalProps = { onClose: (...args: any[]) => void onCreate: (...args: any[]) => void - token: string } export const CreateAccessTokenModal: React.FunctionComponent = ({ onClose, onCreate, - token, }: CreateAccessTokenModalProps) => { + const { accessToken } = React.useContext(SynapseContext) const [tokenName, setTokenName] = React.useState('') const [viewAccess, setViewAccess] = React.useState(true) const [downloadAccess, setDownloadAccess] = React.useState(false) @@ -68,7 +68,7 @@ export const CreateAccessTokenModal: React.FunctionComponent = p /> - + { const { - token, name, sql, updateParentState, @@ -81,6 +85,7 @@ const TopLevelControls = ( getLastQueryRequest, facetAliases, } = props + const { accessToken } = useContext(SynapseContext) const entityId = parseEntityIdFromSqlStatement(sql) const [isFileView, setIsFileView] = useState(false) @@ -102,11 +107,11 @@ const TopLevelControls = ( useEffect(() => { const getIsFileView = async () => { - const entityData = await SynapseClient.getEntity(token, entityId) + const entityData = await SynapseClient.getEntity(accessToken, entityId) setIsFileView(entityData.concreteType.includes('EntityView')) } getIsFileView() - }, [entityId, token]) + }, [entityId, accessToken]) const refresh = () => { executeQueryRequest!(getLastQueryRequest!()) @@ -130,10 +135,16 @@ const TopLevelControls = ( } const showFacetFilter = topLevelControlsState?.showFacetFilter return ( -
-

+
+

- +
{customControls && @@ -165,10 +176,7 @@ const TopLevelControls = ( return ( - setControlState(key) - } - token={token} + onDownloadFiles={() => setControlState(key)} queryResultBundle={data} queryBundleRequest={getLastQueryRequest!()} isFileView={isFileView && !hideDownload} diff --git a/src/lib/containers/synapse_form_wrapper/SynapseFormSubmissionsGrid.tsx b/src/lib/containers/synapse_form_wrapper/SynapseFormSubmissionsGrid.tsx index 418ad45f89..dcc4b9618c 100644 --- a/src/lib/containers/synapse_form_wrapper/SynapseFormSubmissionsGrid.tsx +++ b/src/lib/containers/synapse_form_wrapper/SynapseFormSubmissionsGrid.tsx @@ -16,9 +16,9 @@ import Modal from 'react-bootstrap/Modal' import moment from 'moment' import { SRC_SIGN_IN_CLASS } from '../../utils/SynapseConstants' import NoSubmissionsIcon from '../../assets/icons/json-form-tool-no-submissions.svg' +import { SynapseContext } from '../../utils/SynapseContext' export type SynapseFormSubmissionGridProps = { - token?: string formGroupId: string pathpart: string formClass?: string @@ -74,6 +74,8 @@ export default class SynapseFormSubmissionGrid extends React.Component< ], } + static contextType = SynapseContext + constructor(props: SynapseFormSubmissionGridProps) { super(props) this.state = { @@ -89,14 +91,7 @@ export default class SynapseFormSubmissionGrid extends React.Component< } async componentDidMount() { - await this.refresh(this.props.token) - } - - async componentDidUpdate(prevProps: SynapseFormSubmissionGridProps) { - const shouldUpdate = this.props.token !== prevProps.token - if (shouldUpdate) { - await this.refresh(this.props.token) - } + await this.refresh(this.context.accessToken) } async refresh(token?: string) { @@ -114,7 +109,7 @@ export default class SynapseFormSubmissionGrid extends React.Component< this.setState({ isLoading: true, }) - const token = this.props.token + const token = this.context.accessToken const groupId = this.props.formGroupId try { const cleanUpName = (item: FormData): FormData => { @@ -344,7 +339,7 @@ export default class SynapseFormSubmissionGrid extends React.Component< aria-label="delete" onClick={() => this.setModalConfirmationState( - this.props.token!, + this.context.accessToken!, dataFileRecord.formDataId!, ) } @@ -438,8 +433,8 @@ export default class SynapseFormSubmissionGrid extends React.Component< return (
- {this.renderLoading(this.props.token, this.state.isLoading)} - {this.renderUnauthenticatedView(this.props.token)} + {this.renderLoading(this.context.accessToken, this.state.isLoading)} + {this.renderUnauthenticatedView(this.context.accessToken)} {!this.state.isLoading && (
diff --git a/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.md b/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.md index f828a2338b..7bd60a7074 100644 --- a/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.md +++ b/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.md @@ -6,7 +6,6 @@ fileNamePath="study.submission_name" formUiSchemaEntityId="syn20692911" formNavSchemaEntityId="syn20968007" isWizardMode={true} -token={accessToken} formTitle="Your Contribution Request" formClass="contribution-request" /> diff --git a/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.tsx b/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.tsx index ee4bf09e09..2780b83c74 100644 --- a/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.tsx +++ b/src/lib/containers/synapse_form_wrapper/SynapseFormWrapper.tsx @@ -6,6 +6,7 @@ import Alert from 'react-bootstrap/Alert' import { UiSchema } from 'react-jsonschema-form' import { SynapseClient } from '../../utils' import { SRC_SIGN_IN_CLASS } from '../../utils/SynapseConstants' +import { SynapseContext } from '../../utils/SynapseContext' import { FileEntity, FormData } from '../../utils/synapseTypes/' import SynapseForm from './SynapseForm' import { StatusEnum } from './types' @@ -22,7 +23,6 @@ export type SynapseFormWrapperProps = { formSchemaEntityId: string // Synapse file that contains the form schema. formUiSchemaEntityId: string // Synapse file that contains the form ui schema. formNavSchemaEntityId: string //Synapse file that consists screen nav schema - token?: string // user's access token searchParams?: UploadToolSearchParams isWizardMode?: boolean // if we are displaying the form in wizard mode fileNamePath: string // path in data to specify the name of saved file @@ -55,6 +55,7 @@ class SynapseFormWrapper extends React.Component< SynapseFormWrapperProps, SynapseFormWrapperState > { + static contextType = SynapseContext constructor(props: SynapseFormWrapperProps) { super(props) this.state = { @@ -64,14 +65,7 @@ class SynapseFormWrapper extends React.Component< } async componentDidMount() { - await this.getData(this.props.token) - } - - async componentDidUpdate(prevProps: SynapseFormWrapperProps) { - const shouldUpdate = this.props.token !== prevProps.token - if (shouldUpdate) { - await this.getData(this.props.token) - } + await this.getData(this.context.accessToken) } //gets a file entity with content @@ -234,7 +228,7 @@ class SynapseFormWrapper extends React.Component< isLoading: true, }) - await SynapseClient.submitFormData(this.state.formDataId!, this.props.token) + await SynapseClient.submitFormData(this.state.formDataId!, this.context.accessToken) this.finishedProcessing(StatusEnum.SUBMIT_SUCCESS, 'File Submitted') } @@ -244,7 +238,7 @@ class SynapseFormWrapper extends React.Component< ): Promise => { fileName = `${fileName}.json` const fileUploadComplete = await SynapseClient.uploadFile( - this.props.token, + this.context.accessToken, fileName, fileContentsBlob, ) @@ -264,14 +258,14 @@ class SynapseFormWrapper extends React.Component< this.state.formDataId, fileName, newFileHandleId, - this.props.token!, + this.context.accessToken!, ) } else { formData = await SynapseClient.createFormData( formGroupId, fileName, newFileHandleId, - this.props.token!, + this.context.accessToken!, ) } @@ -347,7 +341,7 @@ class SynapseFormWrapper extends React.Component< ): JSX.Element => { if ( includes([StatusEnum.ERROR, StatusEnum.ERROR_CRITICAL], state.status) && - props.token && + this.context.accessToken && state.isLoading ) { return ( @@ -408,7 +402,7 @@ class SynapseFormWrapper extends React.Component<
{this.renderNotification(this.state.notification)} {this.renderLoader(this.state, this.props)} - {this.renderUnauthenticatedView(this.props.token)} + {this.renderUnauthenticatedView(this.context.accessToken)} {this.isReadyToDisplayForm(this.state) && (
diff --git a/src/lib/containers/synapse_table_functions/renderTableCell.tsx b/src/lib/containers/synapse_table_functions/renderTableCell.tsx index c13af05de9..331a982c5c 100644 --- a/src/lib/containers/synapse_table_functions/renderTableCell.tsx +++ b/src/lib/containers/synapse_table_functions/renderTableCell.tsx @@ -38,7 +38,6 @@ export const renderTableCell = ({ selectColumns, columnModels, tableEntityId, - token, }: { entityColumnIndicies: number[] userColumnIndicies: number[] @@ -59,7 +58,6 @@ export const renderTableCell = ({ selectColumns: SelectColumn[] | undefined columnModels: ColumnModel[] | undefined tableEntityId?: string - token: string | undefined }): React.ReactNode => { const isShortString = ( s: string, @@ -132,7 +130,6 @@ export const renderTableCell = ({ return( ) } diff --git a/src/lib/containers/table/SynapseTable.tsx b/src/lib/containers/table/SynapseTable.tsx index 8936800ae5..3fb8d78f88 100644 --- a/src/lib/containers/table/SynapseTable.tsx +++ b/src/lib/containers/table/SynapseTable.tsx @@ -48,6 +48,7 @@ import DirectDownload from '../DirectDownload' import SearchResultsNotFound from './SearchResultsNotFound' import { DEFAULT_PAGE_SIZE } from '../../utils/SynapseConstants' import AddToDownloadListV2 from '../AddToDownloadListV2' +import { SynapseContext } from '../../utils/SynapseContext' export const EMPTY_HEADER: EntityHeader = { id: '', @@ -101,7 +102,7 @@ export type SynapseTableProps = { showAccessColumn?: boolean showDownloadColumn?: boolean columnLinks?: LabelLinkConfig - hideDownload?: boolean + hideDownload?: boolean isRowSelectionVisible?: boolean } @@ -151,6 +152,8 @@ export default class SynapseTable extends React.Component< this.getEntityHeadersInData = this.getEntityHeadersInData.bind(this) } + static contextType = SynapseContext + // instance variables resizer: any tableElement: HTMLTableElement | null | undefined = undefined @@ -175,7 +178,6 @@ export default class SynapseTable extends React.Component< : true } componentDidUpdate(prevProps: QueryWrapperChildProps & SynapseTableProps) { - this.getEntityHeadersInData(prevProps.token !== this.props.token) this.getTableConcreteType(prevProps) this.enableResize() } @@ -183,13 +185,11 @@ export default class SynapseTable extends React.Component< public async getTableConcreteType( prevProps: QueryWrapperChildProps & SynapseTableProps, ) { - const { data, token } = this.props + const token = this.context.accessToken + const { data } = this.props if (!data) { return - } else if ( - this.state.isFetchingEntityVersion && - prevProps.token === this.props.token - ) { + } else if (this.state.isFetchingEntityVersion) { return } const currentTableId = data?.queryResult.queryResults.tableId @@ -223,7 +223,7 @@ export default class SynapseTable extends React.Component< } public async getEntityHeadersInData(forceRefresh: boolean) { - const { data, token } = this.props + const { data } = this.props if (!data) { return } else if (this.state.isFetchingEntityHeaders && !forceRefresh) { @@ -267,7 +267,10 @@ export default class SynapseTable extends React.Component< referenceList.forEach(el => { mapEntityIdToHeader[el.targetId] = EMPTY_HEADER }) - const data = await SynapseClient.getEntityHeaders(referenceList, token) + const data = await SynapseClient.getEntityHeaders( + referenceList, + this.context.accessToken, + ) const { results } = data results.forEach(el => { mapEntityIdToHeader[el.id] = el @@ -282,7 +285,10 @@ export default class SynapseTable extends React.Component< const ids = Array.from(distinctUserIds) // TODO: Grab Team Badge try { - const data = await SynapseClient.getGroupHeadersBatch(ids, token) + const data = await SynapseClient.getGroupHeadersBatch( + ids, + this.context.accessToken, + ) data.children.forEach(el => { if (el.isIndividual) { userPorfileIds.push(el.ownerId) @@ -298,7 +304,7 @@ export default class SynapseTable extends React.Component< try { const data = await getUserProfileWithProfilePicAttached( userPorfileIds, - token, + this.context.accessToken, ) data.list.forEach((el: UserProfile) => { mapUserIdToHeader[el.ownerId] = el @@ -328,7 +334,6 @@ export default class SynapseTable extends React.Component< data, isLoading = true, unitDescription, - token, showBarChart, topLevelControlsState, } = this.props @@ -348,7 +353,7 @@ export default class SynapseTable extends React.Component< const hasResults = data.queryResult.queryResults.rows.length > 0 if (!hasResults) { if (queryRequest.query.additionalFilters) { - return () + return } else { return (
@@ -361,10 +366,7 @@ export default class SynapseTable extends React.Component< } } const table = ( - -
- {this.renderTable(headers, columnModels, facets, rows)} -
+
{this.renderTable(headers, columnModels, facets, rows)}
) const content = ( <> @@ -377,7 +379,6 @@ export default class SynapseTable extends React.Component< }) }} queryBundleRequest={queryRequest} - token={token} /> )} {!showFacetFilter && @@ -392,7 +393,6 @@ export default class SynapseTable extends React.Component< style={{ fontSize: 15 }} unitDescription={unitDescription} lastQueryRequest={queryRequest} - token={token} frontText={'Showing'} applyChanges={(newFacets: FacetColumnRequest[]) => this.applyChangesFromQueryFilter(newFacets) @@ -453,7 +453,6 @@ export default class SynapseTable extends React.Component< hasMoreData, showAccessColumn, showDownloadColumn, - token, isRowSelectionVisible, } = this.props @@ -496,7 +495,8 @@ export default class SynapseTable extends React.Component< showAccessColumn && this.state.isFileView const isShowDownloadColumn: boolean | undefined = showDownloadColumn && this.state.isFileView - const isShowingAddToV2DownloadListColumn: boolean = this.state.isFileView && SynapseClient.isInSynapseExperimentalMode() + const isShowingAddToV2DownloadListColumn: boolean = + this.state.isFileView && SynapseClient.isInSynapseExperimentalMode() /* min height ensure if no rows are selected that a dropdown menu is still accessible */ const tableEntityId: string = lastQueryRequest?.entityId @@ -504,7 +504,6 @@ export default class SynapseTable extends React.Component<
{this.state.isDownloadConfirmationOpen && ( )} @@ -728,11 +727,10 @@ export default class SynapseTable extends React.Component< isShowingDownloadColumn: boolean | undefined, isShowingAddToV2DownloadListColumn: boolean, isRowSelectionVisible: boolean | undefined, - tableEntityId: string | undefined + tableEntityId: string | undefined, ) { const rowsFormatted: JSX.Element[] = [] const { - token, data, isColumnSelected, selectedRowIndices, @@ -833,7 +831,6 @@ export default class SynapseTable extends React.Component< columnModels, columnName, tableEntityId, - token, })} ) @@ -850,7 +847,6 @@ export default class SynapseTable extends React.Component< key={rowSynapseId} entityId={rowSynapseId} entityVersionNumber={entityVersionNumber} - token={token} > , ) @@ -860,24 +856,22 @@ export default class SynapseTable extends React.Component< rowContent.unshift( - + , ) } if (isShowingAddToV2DownloadListColumn) { rowContent.unshift( - + , ) } @@ -936,12 +930,7 @@ export default class SynapseTable extends React.Component< lastQueryRequest: QueryBundleRequest, ) { const { sortedColumnSelection, columnIconSortState } = this.state - const { - facetAliases = {}, - isColumnSelected, - token, - lockedFacet, - } = this.props + const { facetAliases = {}, isColumnSelected, lockedFacet } = this.props const tableColumnHeaderElements: JSX.Element[] = headers.map( (column: SelectColumn, index: number) => { const isHeaderSelected = isColumnSelected!.includes(column.name) @@ -991,7 +980,6 @@ export default class SynapseTable extends React.Component< facet, columnModel, lastQueryRequest, - token, facetAliases, )} {this.isSortableColumn(column.columnType) && ( @@ -1037,14 +1025,14 @@ export default class SynapseTable extends React.Component< tableColumnHeaderElements.unshift(
 
- + , ) } if (isShowingAddToV2DownloadListColumn) { tableColumnHeaderElements.unshift(
 
- + , ) } if (isRowSelectionVisible) { @@ -1124,7 +1112,6 @@ export default class SynapseTable extends React.Component< facetColumnResult: FacetColumnResultValues, columnModel: ColumnModel, lastQueryRequest: QueryBundleRequest, - token?: string, facetAliases?: {}, ) { return ( @@ -1132,7 +1119,6 @@ export default class SynapseTable extends React.Component< containerAs="Dropdown" facetValues={facetColumnResult.facetValues} columnModel={columnModel!} - token={token} facetAliases={facetAliases} onChange={(facetNamesMap: {}) => { applyMultipleChangesToValuesColumn( diff --git a/src/lib/containers/table/table-top/DownloadOptions.tsx b/src/lib/containers/table/table-top/DownloadOptions.tsx index 9d90466757..4297e93002 100644 --- a/src/lib/containers/table/table-top/DownloadOptions.tsx +++ b/src/lib/containers/table/table-top/DownloadOptions.tsx @@ -8,6 +8,7 @@ import { } from '../../../utils/synapseTypes' import ProgrammaticOptions from './ProgrammaticOptions' import ModalDownload from '../../../containers/ModalDownload' +import { SynapseContext } from '../../../utils/SynapseContext' export const DOWNLOAD_OPTIONS_CONTAINER_CLASS = 'SRC-download-options-container' @@ -16,7 +17,6 @@ type DownloadOptionsProps = { isUnauthenticated?: boolean isFileView?: boolean darkTheme?: boolean - token: string | undefined queryResultBundle?: QueryResultBundle queryBundleRequest: QueryBundleRequest } @@ -25,6 +25,7 @@ export const DOWNLOAD_FILES_MENU_TEXT = 'Add To Download List' const tooltipDownloadId = 'download' export const DownloadOptions: React.FunctionComponent = props => { + const { accessToken } = React.useContext(SynapseContext) const [showLoginModal, setShowLoginModal] = React.useState(false) const [showExportMetadata, setShowExportMetadata] = React.useState(false) const [showProgrammaticOptions, setShowProgrammaticOptions] = React.useState( @@ -34,7 +35,6 @@ export const DownloadOptions: React.FunctionComponent = pr onDownloadFiles, queryResultBundle, queryBundleRequest, - token, darkTheme = true, } = props @@ -46,7 +46,7 @@ export const DownloadOptions: React.FunctionComponent = pr tooltipText={'Download Options'} size="lg" darkTheme={darkTheme} - icon={"download"} + icon={'download'} > = pr {props.isFileView && ( - props.token ? onDownloadFiles() : setShowLoginModal(true) + accessToken ? onDownloadFiles() : setShowLoginModal(true) } > {DOWNLOAD_FILES_MENU_TEXT} @@ -88,7 +88,6 @@ export const DownloadOptions: React.FunctionComponent = pr setShowExportMetadata(false)} queryBundleRequest={queryBundleRequest} - token={token} /> ) } diff --git a/src/lib/containers/widgets/FileHandleLink.tsx b/src/lib/containers/widgets/FileHandleLink.tsx index b4f0562353..72d48488b4 100644 --- a/src/lib/containers/widgets/FileHandleLink.tsx +++ b/src/lib/containers/widgets/FileHandleLink.tsx @@ -1,10 +1,10 @@ import { FileHandleAssociateType } from '../../utils/synapseTypes' -import React from 'react' +import React, { useContext } from 'react' import { SynapseConstants, SynapseClient } from '../../utils' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { SynapseContext } from '../../utils/SynapseContext' type FileHandleLinkProps = { - token: string | undefined fileHandleId: string redirect?: boolean showDownloadIcon: boolean @@ -15,7 +15,6 @@ type FileHandleLinkProps = { } export const FileHandleLink = (props: FileHandleLinkProps) => { const { - token, fileHandleId, showDownloadIcon, tableEntityConcreteType, @@ -24,7 +23,7 @@ export const FileHandleLink = (props: FileHandleLinkProps) => { redirect = false, displayValue, } = props - + const { accessToken } = useContext(SynapseContext) if (!tableEntityConcreteType) { // still loading return <> @@ -38,19 +37,20 @@ export const FileHandleLink = (props: FileHandleLinkProps) => {