-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
14 changed files
with
314 additions
and
2 deletions.
There are no files selected for viewing
103 changes: 103 additions & 0 deletions
103
packages/synapse-react-client/src/components/ProjectStorage/ProjectDataAvailability.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import React from 'react' | ||
import { Box, SxProps, Tooltip, Typography } from '@mui/material' | ||
import { useSynapseContext } from '../../utils' | ||
import { useProjectStorageUsage } from '../../synapse-queries' | ||
import { SYNAPSE_STORAGE_LOCATION_ID } from '../../synapse-client' | ||
import HelpPopover from '../HelpPopover' | ||
import { calculateFriendlyFileSize } from '../../utils/functions/calculateFriendlyFileSize' | ||
|
||
export type ProjectDataAvailabilityProps = { | ||
projectId?: string | ||
sx?: SxProps | ||
} | ||
const usageBarWidth = 142 //px | ||
|
||
export const ProjectDataAvailability: React.FunctionComponent< | ||
ProjectDataAvailabilityProps | ||
> = ({ projectId, sx }) => { | ||
const { accessToken } = useSynapseContext() | ||
const isLoggedIn = !!accessToken | ||
const { data } = useProjectStorageUsage(projectId!, { | ||
enabled: !!projectId && isLoggedIn, | ||
}) | ||
|
||
const projectDataUsageArray = data?.locations.filter( | ||
v => parseInt(v.storageLocationId) == SYNAPSE_STORAGE_LOCATION_ID, | ||
) | ||
const synapseStorageUsage = | ||
projectDataUsageArray?.length == 1 ? projectDataUsageArray[0] : undefined | ||
if (!synapseStorageUsage) { | ||
return <></> | ||
} | ||
const { sumFileBytes = 0, maxAllowedFileBytes = 1 } = synapseStorageUsage | ||
if (maxAllowedFileBytes == 0) { | ||
return <></> | ||
} | ||
const usageBarFilledPx = Math.min( | ||
Math.round((sumFileBytes / maxAllowedFileBytes) * usageBarWidth), | ||
usageBarWidth, | ||
) | ||
const friendlySumFileBytes = calculateFriendlyFileSize(sumFileBytes, 1) | ||
const friendlyMaxAllowedFileBytes = calculateFriendlyFileSize( | ||
maxAllowedFileBytes, | ||
0, | ||
) | ||
return ( | ||
<Box | ||
display="flex" | ||
flexDirection="column" | ||
width="210px" | ||
fontFamily="DM Sans" | ||
color="white" | ||
px="10px" | ||
sx={sx} | ||
> | ||
<Box display="flex" flexDirection="row" gap="5px"> | ||
<Typography | ||
sx={{ | ||
// match current styles in Project metadata | ||
fontWeight: 700, | ||
fontSize: '16px', | ||
}} | ||
> | ||
Data Availability{' '} | ||
</Typography>{' '} | ||
<HelpPopover | ||
markdownText="Hosting Plan Options: | ||
- Basic Plan: Free, for sharing small datasets (<100GB) with self-service setup. No direct support. | ||
- Self-Managed Plan: Ideal for data longevity, FAIR principles, and NIH compliance. Includes consultation services and data access management tools. | ||
- Data Coordination Plan: For large, multi-institutional projects, with personalized consulting, data curation, and a custom data portal." | ||
helpUrl="https://help.synapse.org/docs/Sage-Offerings.2965078125.html" | ||
/> | ||
</Box> | ||
{synapseStorageUsage.maxAllowedFileBytes && ( | ||
<Tooltip | ||
title={`Using ${friendlySumFileBytes} out of ${friendlyMaxAllowedFileBytes}`} | ||
> | ||
<Box display="flex" flexDirection="row" gap="5px" alignItems="center"> | ||
<Typography variant="body1" fontSize="12px"> | ||
0 | ||
</Typography> | ||
{/* Progress Bar */} | ||
<Box | ||
width={`${usageBarWidth}px`} | ||
height="4px" | ||
sx={{ backgroundColor: 'white', borderRadius: '50px' }} | ||
> | ||
<Box | ||
width={`${usageBarFilledPx}px`} | ||
height="4px" | ||
sx={{ backgroundColor: '#EDC766', borderRadius: '50px' }} | ||
></Box> | ||
</Box> | ||
<Typography variant="body1" fontSize="12px"> | ||
{friendlyMaxAllowedFileBytes} | ||
</Typography> | ||
</Box> | ||
</Tooltip> | ||
)} | ||
</Box> | ||
) | ||
} | ||
|
||
export default ProjectDataAvailability |
74 changes: 74 additions & 0 deletions
74
packages/synapse-react-client/src/components/ProjectStorage/ProjectStorage.stories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import ProjectDataAvailability from './ProjectDataAvailability' | ||
import { MOCK_REPO_ORIGIN } from 'src/utils/functions/getEndpoint' | ||
import { getUserProfileHandlers } from 'src/mocks/msw/handlers/userProfileHandlers' | ||
import { getEntityHandlers } from 'src/mocks/msw/handlers/entityHandlers' | ||
import { getProjectStorageHandlers } from 'src/mocks/msw/handlers/projectStorageHandlers' | ||
import { | ||
OVER_LIMIT_PROJECT_ID, | ||
UNDER_LIMIT_PROJECT_ID, | ||
} from 'src/mocks/projectStorage/mockProjectStorageLimits' | ||
|
||
const meta = { | ||
title: 'Synapse/ProjectStorage', | ||
component: ProjectDataAvailability, | ||
argTypes: { | ||
isAuthenticated: { | ||
type: 'boolean', | ||
}, | ||
}, | ||
args: { | ||
isAuthenticated: true, | ||
}, | ||
} satisfies Meta | ||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
|
||
export const ProjectDataUnderLimit: Story = { | ||
args: { | ||
projectId: UNDER_LIMIT_PROJECT_ID, | ||
sx: { backgroundColor: '#375574' }, | ||
}, | ||
parameters: { | ||
stack: 'mock', | ||
msw: { | ||
handlers: [ | ||
...getUserProfileHandlers(MOCK_REPO_ORIGIN), | ||
...getEntityHandlers(MOCK_REPO_ORIGIN), | ||
...getProjectStorageHandlers(MOCK_REPO_ORIGIN), | ||
], | ||
}, | ||
}, | ||
} | ||
|
||
export const ProjectDataOverLimit: Story = { | ||
args: { | ||
projectId: OVER_LIMIT_PROJECT_ID, | ||
sx: { backgroundColor: '#375574' }, | ||
}, | ||
|
||
parameters: { | ||
stack: 'mock', | ||
msw: { | ||
handlers: [ | ||
...getUserProfileHandlers(MOCK_REPO_ORIGIN), | ||
...getEntityHandlers(MOCK_REPO_ORIGIN), | ||
...getProjectStorageHandlers(MOCK_REPO_ORIGIN), | ||
], | ||
}, | ||
}, | ||
} | ||
|
||
export const ProjectDataStorageNotSet: Story = { | ||
args: { projectId: 'syn31415123' }, | ||
parameters: { | ||
stack: 'mock', | ||
msw: { | ||
handlers: [ | ||
...getUserProfileHandlers(MOCK_REPO_ORIGIN), | ||
...getEntityHandlers(MOCK_REPO_ORIGIN), | ||
...getProjectStorageHandlers(MOCK_REPO_ORIGIN), | ||
], | ||
}, | ||
}, | ||
} |
4 changes: 4 additions & 0 deletions
4
packages/synapse-react-client/src/components/ProjectStorage/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import ProjectDataAvailability from './ProjectDataAvailability' | ||
import type { ProjectDataAvailabilityProps } from './ProjectDataAvailability' | ||
export { ProjectDataAvailability, ProjectDataAvailabilityProps } | ||
export default ProjectDataAvailability |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
packages/synapse-react-client/src/mocks/msw/handlers/projectStorageHandlers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { rest } from 'msw' | ||
import { PROJECT_STORAGE_USAGE } from '../../../utils/APIConstants' | ||
import { BackendDestinationEnum, getEndpoint } from '../../../utils/functions' | ||
import { | ||
mockProjectStorageUsageOverLimit, | ||
mockProjectStorageUsageUnderLimit, | ||
OVER_LIMIT_PROJECT_ID, | ||
UNDER_LIMIT_PROJECT_ID, | ||
} from '../../../mocks/projectStorage/mockProjectStorageLimits' | ||
|
||
export const getProjectStorageHandlers = ( | ||
backendOrigin = getEndpoint(BackendDestinationEnum.REPO_ENDPOINT), | ||
) => [ | ||
rest.get( | ||
`${backendOrigin}${PROJECT_STORAGE_USAGE(OVER_LIMIT_PROJECT_ID)}`, | ||
async (req, res, ctx) => { | ||
return res(ctx.status(201), ctx.json(mockProjectStorageUsageOverLimit)) | ||
}, | ||
), | ||
rest.get( | ||
`${backendOrigin}${PROJECT_STORAGE_USAGE(UNDER_LIMIT_PROJECT_ID)}`, | ||
async (req, res, ctx) => { | ||
return res(ctx.status(201), ctx.json(mockProjectStorageUsageUnderLimit)) | ||
}, | ||
), | ||
] |
41 changes: 41 additions & 0 deletions
41
packages/synapse-react-client/src/mocks/projectStorage/mockProjectStorageLimits.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { ProjectStorageUsage } from '@sage-bionetworks/synapse-types' | ||
import { SYNAPSE_STORAGE_LOCATION_ID } from '../../synapse-client' | ||
|
||
export const OVER_LIMIT_PROJECT_ID = 'syn54321' | ||
export const UNDER_LIMIT_PROJECT_ID = 'syn12345' | ||
|
||
export const mockProjectStorageUsageOverLimit: ProjectStorageUsage = { | ||
projectId: OVER_LIMIT_PROJECT_ID, | ||
locations: [ | ||
{ | ||
storageLocationId: `${SYNAPSE_STORAGE_LOCATION_ID}`, | ||
sumFileBytes: 1200000000, // 1.2 GB | ||
maxAllowedFileBytes: 1073741824, // 1 GB limit | ||
isOverLimit: true, // Over the limit | ||
}, | ||
{ | ||
storageLocationId: 'location-2', | ||
sumFileBytes: 100000000, | ||
maxAllowedFileBytes: 1073741824, | ||
isOverLimit: false, | ||
}, | ||
], | ||
} | ||
|
||
export const mockProjectStorageUsageUnderLimit: ProjectStorageUsage = { | ||
projectId: UNDER_LIMIT_PROJECT_ID, | ||
locations: [ | ||
{ | ||
storageLocationId: `${SYNAPSE_STORAGE_LOCATION_ID}`, | ||
sumFileBytes: 500000000, | ||
maxAllowedFileBytes: 1073741824, | ||
isOverLimit: false, // Under the limit | ||
}, | ||
{ | ||
storageLocationId: 'location-2', | ||
sumFileBytes: 1000, | ||
maxAllowedFileBytes: 1073741824, | ||
isOverLimit: false, | ||
}, | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
packages/synapse-react-client/src/synapse-queries/entity/useProjectStorage.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Hooks to access Project Storage in Synapse | ||
*/ | ||
import { useQuery, UseQueryOptions } from '@tanstack/react-query' | ||
import SynapseClient from '../../synapse-client' | ||
import { SynapseClientError, useSynapseContext } from '../../utils' | ||
import { ProjectStorageUsage } from '@sage-bionetworks/synapse-types' | ||
|
||
export function useProjectStorageUsage( | ||
projectId: string, | ||
options?: Partial<UseQueryOptions<ProjectStorageUsage, SynapseClientError>>, | ||
) { | ||
const { accessToken, keyFactory } = useSynapseContext() | ||
return useQuery({ | ||
...options, | ||
queryKey: keyFactory.getProjectStorageUsageKey(projectId), | ||
queryFn: () => SynapseClient.getProjectStorageUsage(projectId, accessToken), | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export type ProjectStorageUsage = { | ||
projectId: string // The ID of the project | ||
locations: ProjectStorageLocationUsage[] // List of storage location usages | ||
} | ||
|
||
export type ProjectStorageLocationUsage = { | ||
storageLocationId: string // The ID of the storage location | ||
sumFileBytes: number // The total number of bytes of files currently associated with this project storage location | ||
maxAllowedFileBytes?: number // The total number of allowed bytes for this project storage location (optional) | ||
isOverLimit: boolean // Whether the project storage location is over its limit | ||
} | ||
|
||
export type ProjectStorageLocationLimit = { | ||
projectId: string // The ID of the project | ||
storageLocationId: string // The ID of the storage location | ||
maxAllowedFileBytes: string // Sets the limit on the number of file bytes for this storage location | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters