synapse-react-client 4.0.17 → 4.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/SWC.index.d.ts.map +1 -1
- package/dist/SWC.index.js +1 -1
- package/dist/SWC.index.js.map +1 -1
- package/dist/assets/homepage/BlinkingLiveIcon.d.ts +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/CertificationRequirement.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/UnmanagedACTAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/ValidationRequirement.js.map +1 -1
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.d.ts.map +1 -1
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.js +56 -54
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.js.map +1 -1
- package/dist/components/Authentication/PasswordField.d.ts +1 -1
- package/dist/components/Authentication/PasswordField.d.ts.map +1 -1
- package/dist/components/Authentication/PasswordField.js.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js +1 -2
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
- package/dist/components/Authentication/UsernamePasswordForm.d.ts.map +1 -1
- package/dist/components/Authentication/UsernamePasswordForm.js +32 -29
- package/dist/components/Authentication/UsernamePasswordForm.js.map +1 -1
- package/dist/components/CardContainer/CardLink.d.ts +2 -2
- package/dist/components/CardContainer/CardLink.d.ts.map +1 -1
- package/dist/components/CardDeck/CardDeckCardProps.d.ts.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js +106 -103
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/MembershipRequestForm.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/MembershipRequestForm.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.js.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.d.ts.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.js +4 -4
- package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
- package/dist/components/CreateTableViewWizard/TableNameForm.js +6 -6
- package/dist/components/CreateTableViewWizard/TableNameForm.js.map +1 -1
- package/dist/components/CrispChat/CrispChat.js +4 -4
- package/dist/components/CrispChat/CrispChat.js.map +1 -1
- package/dist/components/DataGrid/utils/json-rx/JsonRxResponseComplete.js.map +1 -1
- package/dist/components/DownloadCart/RequestDownloadCard.js +14 -14
- package/dist/components/DownloadCart/RequestDownloadCard.js.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.d.ts.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
- package/dist/components/EntityCitation/EntityCitationUtils.js.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
- package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
- package/dist/components/EntityFinder/EntityIdTextField.d.ts +17 -0
- package/dist/components/EntityFinder/EntityIdTextField.d.ts.map +1 -0
- package/dist/components/EntityFinder/EntityIdTextField.js +35 -0
- package/dist/components/EntityFinder/EntityIdTextField.js.map +1 -0
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.d.ts.map +1 -1
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js +22 -16
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js.map +1 -1
- package/dist/components/FeaturedDataTabs/FacetPlotsCardGrid.js.map +1 -1
- package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
- package/dist/components/FullWidthAlert/FullWidthAlert.d.ts.map +1 -1
- package/dist/components/FullWidthAlert/FullWidthAlert.js.map +1 -1
- package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.d.ts.map +1 -1
- package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.js.map +1 -1
- package/dist/components/Markdown/widget/MarkdownSynapsePlot.js.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts.map +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.d.ts.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.js +34 -33
- package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.d.ts.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.d.ts.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.js.map +1 -1
- package/dist/components/Resources/Resources.Desktop.js.map +1 -1
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.d.ts.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
- package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.d.ts.map +1 -1
- package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.js.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.d.ts.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.d.ts.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
- package/dist/components/SynapseTable/SearchV2.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTable.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableUtils.d.ts.map +1 -1
- package/dist/components/SynapseTable/SynapseTableUtils.js.map +1 -1
- package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TanStackTable/TanStackTableUtils.js.map +1 -1
- package/dist/components/TextField/TextField.css +1 -1
- package/dist/components/TextField/TextField.d.ts +14 -3
- package/dist/components/TextField/TextField.d.ts.map +1 -1
- package/dist/components/TextField/TextField.js +41 -43
- package/dist/components/TextField/TextField.js.map +1 -1
- package/dist/components/TextField/TextField.module.js +3 -4
- package/dist/components/TextField/TextField.module.js.map +1 -1
- package/dist/components/TextField/TextField.module.scss +18 -10
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.d.ts.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js +20 -16
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
- package/dist/components/UserCardList/UserCardList.d.ts.map +1 -1
- package/dist/components/UserCardList/UserCardList.js.map +1 -1
- package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.js.map +1 -1
- package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.d.ts.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
- package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
- package/dist/components/doi/CreateOrUpdateDoiModal.js +13 -13
- package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
- package/dist/components/entity/page/title_bar/TitleBarProperties.js +23 -23
- package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
- package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
- package/dist/components/index.js +17 -17
- package/dist/components/styled/StyledFormControl.d.ts +15 -0
- package/dist/components/styled/StyledFormControl.d.ts.map +1 -1
- package/dist/components/styled/StyledFormControl.js +1 -0
- package/dist/components/styled/StyledFormControl.js.map +1 -1
- package/dist/components/styled/index.js +3 -3
- package/dist/components/utils/ConditionalWrapper.d.ts.map +1 -1
- package/dist/components/utils/ConditionalWrapper.js.map +1 -1
- package/dist/components/widgets/ElementWithTooltip.js.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.d.ts.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.js +69 -62
- package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js +27 -26
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js +2 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js +44 -43
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js.map +1 -1
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts +13 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +398 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -0
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +49 -19
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.js +46 -25
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts +0 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js +20 -22
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +25 -27
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -1
- package/dist/features/entity/metadata-task/utils/constants.d.ts +26 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/utils/constants.js +2 -2
- package/dist/features/entity/metadata-task/utils/constants.js.map +1 -1
- package/dist/index.js +17 -17
- package/dist/mockServiceWorker.js +6 -8
- package/dist/mocks/curation/mockCurationTask.d.ts +2 -2
- package/dist/mocks/curation/mockCurationTask.d.ts.map +1 -1
- package/dist/mocks/curation/mockCurationTask.js +9 -5
- package/dist/mocks/curation/mockCurationTask.js.map +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts.map +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.js +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.js.map +1 -1
- package/dist/style/components/_cards.scss +0 -3
- package/dist/style/components/_data-grid-extra.scss +2 -2
- package/dist/style/components/_login.scss +6 -2
- package/dist/style/main.css +1 -1
- package/dist/synapse-client/SynapseClient.d.ts +2 -1
- package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
- package/dist/synapse-client/SynapseClient.js.map +1 -1
- package/dist/synapse-queries/QueryFilterUtils.js.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -0
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js +16 -6
- package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
- package/dist/synapse-queries/dataaccess/useAccessRequirements.d.ts.map +1 -1
- package/dist/synapse-queries/dataaccess/useAccessRequirements.js.map +1 -1
- package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts.map +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.js.map +1 -1
- package/dist/synapse-queries/file/useFiles.d.ts.map +1 -1
- package/dist/synapse-queries/file/useFiles.js.map +1 -1
- package/dist/synapse-queries/termsOfService/useTermsOfService.d.ts.map +1 -1
- package/dist/synapse-queries/termsOfService/useTermsOfService.js.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.d.ts.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
- package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
- package/dist/theme/palette/Palettes.d.ts +2 -2
- package/dist/theme/palette/Palettes.d.ts.map +1 -1
- package/dist/theme/palette/Palettes.js +2 -2
- package/dist/theme/palette/Palettes.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/ThemeTypes.d.ts +5 -6
- package/dist/utils/AppUtils/session/SynapseSessionManager.d.ts.map +1 -1
- package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
- package/dist/utils/featureflag/FeatureFlags.d.ts +12 -0
- package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -0
- package/dist/utils/featureflag/FeatureFlags.js +8 -0
- package/dist/utils/featureflag/FeatureFlags.js.map +1 -0
- package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
- package/dist/utils/functions/queryUtils.js.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.d.ts.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
- package/dist/utils/slots/SlotUtils.d.ts.map +1 -1
- package/dist/utils/slots/SlotUtils.js.map +1 -1
- package/package.json +7 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/CreateChallengeTeam.tsx"],"sourcesContent":["import {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { Alert, Box, Typography } from '@mui/material'\nimport TextField from '../TextField'\nimport { CreateTeamRequest, Team } from '@sage-bionetworks/synapse-types'\nimport useCreateAndRegisterChallengeTeam from './useCreateAndRegisterChallengeTeam'\nimport { isEmpty, noop } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\n\nexport type CreateChallengeTeamProps = {\n challengeId: string\n onCanSubmitChange?: (canSubmit: boolean) => void\n onFinished?: (teamId: string) => void\n}\n\nconst INVITEE_LIMIT = 3\nexport const TOO_MANY_INVITEES_ERROR =\n 'Please limit the initial number of invited members to three. You may add additional members after the team has been created.'\n\nexport type CreateChallengeTeamHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\nexport const CreateChallengeTeam = forwardRef(function CreateChallengeTeam(\n props: CreateChallengeTeamProps,\n ref: ForwardedRef<CreateChallengeTeamHandle>,\n) {\n const { challengeId, onCanSubmitChange = noop, onFinished = noop } = props\n const [team, setTeam] = useState<CreateTeamRequest>({\n name: '',\n description: '',\n })\n const [invitationMessage, setInvitationMessage] = useState('')\n const [rawInvitees, setRawInvitees] = useState('')\n\n const handleTeamUpdate = (update: Partial<Team>) => {\n const updatedTeam: CreateTeamRequest = { ...team, ...update }\n setTeam(updatedTeam)\n }\n\n const { inviteesParseResult, parsedInvitees } = useMemo(() => {\n const inviteesParseResult = parse<string[]>(rawInvitees, {\n delimiter: ',',\n transform(value) {\n return value.trim()\n },\n })\n const parsedInvitees: string[] = inviteesParseResult.data[0] || []\n\n return { inviteesParseResult, parsedInvitees }\n }, [rawInvitees])\n\n const numberOfInvitees = parsedInvitees.length\n const tooManyInvitees = numberOfInvitees > INVITEE_LIMIT\n\n const formDataIsValid = Boolean(\n team && team.name && team.name.length > 1 && !tooManyInvitees,\n )\n\n useEffect(() => {\n onCanSubmitChange(formDataIsValid)\n }, [formDataIsValid, onCanSubmitChange])\n\n const {\n createAndRegisterTeam,\n isPending: mutationIsPending,\n errors,\n } = useCreateAndRegisterChallengeTeam()\n\n useImperativeHandle(
|
|
1
|
+
{"version":3,"file":"CreateChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/CreateChallengeTeam.tsx"],"sourcesContent":["import {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { Alert, Box, Stack, Typography } from '@mui/material'\nimport TextField from '../TextField'\nimport { CreateTeamRequest, Team } from '@sage-bionetworks/synapse-types'\nimport useCreateAndRegisterChallengeTeam from './useCreateAndRegisterChallengeTeam'\nimport { isEmpty, noop } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\n\nexport type CreateChallengeTeamProps = {\n challengeId: string\n onCanSubmitChange?: (canSubmit: boolean) => void\n onFinished?: (teamId: string) => void\n}\n\nconst INVITEE_LIMIT = 3\nexport const TOO_MANY_INVITEES_ERROR =\n 'Please limit the initial number of invited members to three. You may add additional members after the team has been created.'\n\nexport type CreateChallengeTeamHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\nexport const CreateChallengeTeam = forwardRef(function CreateChallengeTeam(\n props: CreateChallengeTeamProps,\n ref: ForwardedRef<CreateChallengeTeamHandle>,\n) {\n const { challengeId, onCanSubmitChange = noop, onFinished = noop } = props\n const [team, setTeam] = useState<CreateTeamRequest>({\n name: '',\n description: '',\n })\n const [invitationMessage, setInvitationMessage] = useState('')\n const [rawInvitees, setRawInvitees] = useState('')\n\n const handleTeamUpdate = (update: Partial<Team>) => {\n const updatedTeam: CreateTeamRequest = { ...team, ...update }\n setTeam(updatedTeam)\n }\n\n const { inviteesParseResult, parsedInvitees } = useMemo(() => {\n const inviteesParseResult = parse<string[]>(rawInvitees, {\n delimiter: ',',\n transform(value) {\n return value.trim()\n },\n })\n const parsedInvitees: string[] = inviteesParseResult.data[0] || []\n\n return { inviteesParseResult, parsedInvitees }\n }, [rawInvitees])\n\n const numberOfInvitees = parsedInvitees.length\n const tooManyInvitees = numberOfInvitees > INVITEE_LIMIT\n\n const formDataIsValid = Boolean(\n team && team.name && team.name.length > 1 && !tooManyInvitees,\n )\n\n useEffect(() => {\n onCanSubmitChange(formDataIsValid)\n }, [formDataIsValid, onCanSubmitChange])\n\n const {\n createAndRegisterTeam,\n isPending: mutationIsPending,\n errors,\n } = useCreateAndRegisterChallengeTeam()\n\n useImperativeHandle(ref, () => {\n return {\n submit() {\n if (!formDataIsValid) {\n console.warn(\n 'Attempted to submit when form data was not valid. Nothing will happen.',\n )\n return\n }\n createAndRegisterTeam(\n team,\n challengeId,\n parsedInvitees,\n invitationMessage,\n )\n .then(([newTeam]) => {\n onFinished(newTeam.id)\n })\n .catch(() => {\n // The hook will return errors, so no need to handle them here\n })\n },\n }\n }, [\n formDataIsValid,\n parsedInvitees,\n createAndRegisterTeam,\n team,\n challengeId,\n invitationMessage,\n onFinished,\n ])\n\n return (\n <Stack gap={2}>\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n Create a new team for this Challenge!\n </Typography>\n <TextField\n id=\"name\"\n label=\"Team Name\"\n value={team.name}\n fullWidth\n autoFocus\n required\n onChange={event => handleTeamUpdate({ name: event.target.value })}\n disabled={mutationIsPending}\n />\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"description\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Team Description</Box>\n </Box>\n }\n value={team.description}\n fullWidth\n multiline\n rows={4}\n onChange={event =>\n handleTeamUpdate({ description: event.target.value })\n }\n disabled={mutationIsPending}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"message\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Recruitment Message</Box>\n </Box>\n }\n value={invitationMessage}\n fullWidth\n multiline\n rows={4}\n onChange={event => setInvitationMessage(event.target.value)}\n disabled={mutationIsPending}\n />\n </Box>\n <TextField\n id=\"invitees\"\n label=\"Emails of Additional Members to Invite (max 3)\"\n placeholder=\"Enter emails separated by comma\"\n value={rawInvitees}\n fullWidth\n onChange={event => setRawInvitees(event.target.value)}\n disabled={mutationIsPending}\n />\n {(tooManyInvitees || !isEmpty(inviteesParseResult.errors) || errors) && (\n <Alert severity=\"error\">\n {tooManyInvitees && (\n <Typography variant={'body1'}>{TOO_MANY_INVITEES_ERROR}</Typography>\n )}\n {inviteesParseResult.errors.map((error, index) => (\n <Typography key={index} variant={'body1'}>\n {error.message}\n </Typography>\n ))}\n {errors &&\n errors.map(error => (\n <Typography key={error.reason} variant={'body1'}>\n {error.reason}\n </Typography>\n ))}\n </Alert>\n )}\n </Stack>\n )\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MembershipRequestForm.d.ts","sourceRoot":"","sources":["../../../src/components/ChallengeTeamWizard/MembershipRequestForm.tsx"],"names":[],"mappings":"AAgBA,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,kBAAkB,EAAE,MAAM,IAAI,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IAExC,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"MembershipRequestForm.d.ts","sourceRoot":"","sources":["../../../src/components/ChallengeTeamWizard/MembershipRequestForm.tsx"],"names":[],"mappings":"AAgBA,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,kBAAkB,EAAE,MAAM,IAAI,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IAExC,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,8HA8EhC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MembershipRequestForm.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/MembershipRequestForm.tsx"],"sourcesContent":["import {\n useGetCurrentUserProfile,\n useGetTeam,\n useRequestToJoinTeam,\n} from '@/synapse-queries'\nimport { Alert, Box, TextField, Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport {\n ChangeEvent,\n ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useState,\n} from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype JoinRequestFormProps = {\n teamId: string\n onRequestSubmitted: () => void\n}\n\nexport type MembershipRequestFormHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\n/**\n * Component that provides a form that a user can use to create a MembershipRequest for a Team.\n *\n * To submit the form, pass a ref and call the `submit` handle on the ref.\n */\nexport const MembershipRequestForm = forwardRef(function MembershipRequestForm(\n props: JoinRequestFormProps,\n ref: ForwardedRef<MembershipRequestFormHandle>,\n) {\n const { teamId, onRequestSubmitted = noop } = props\n const [message, setMessage] = useState<string>('')\n\n const { data: userProfile } = useGetCurrentUserProfile()\n\n const {\n data: team,\n status,\n error,\n } = useGetTeam(teamId, { enabled: !!teamId })\n\n const { mutate: requestToJoinTeam } = useRequestToJoinTeam({\n onSuccess: () => {\n onRequestSubmitted()\n },\n })\n const handleMessageChange = (event: ChangeEvent<HTMLTextAreaElement>) => {\n const value = event.target.value\n setMessage(value)\n }\n\n useImperativeHandle(
|
|
1
|
+
{"version":3,"file":"MembershipRequestForm.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/MembershipRequestForm.tsx"],"sourcesContent":["import {\n useGetCurrentUserProfile,\n useGetTeam,\n useRequestToJoinTeam,\n} from '@/synapse-queries'\nimport { Alert, Box, TextField, Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport {\n ChangeEvent,\n ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useState,\n} from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype JoinRequestFormProps = {\n teamId: string\n onRequestSubmitted: () => void\n}\n\nexport type MembershipRequestFormHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\n/**\n * Component that provides a form that a user can use to create a MembershipRequest for a Team.\n *\n * To submit the form, pass a ref and call the `submit` handle on the ref.\n */\nexport const MembershipRequestForm = forwardRef(function MembershipRequestForm(\n props: JoinRequestFormProps,\n ref: ForwardedRef<MembershipRequestFormHandle>,\n) {\n const { teamId, onRequestSubmitted = noop } = props\n const [message, setMessage] = useState<string>('')\n\n const { data: userProfile } = useGetCurrentUserProfile()\n\n const {\n data: team,\n status,\n error,\n } = useGetTeam(teamId, { enabled: !!teamId })\n\n const { mutate: requestToJoinTeam } = useRequestToJoinTeam({\n onSuccess: () => {\n onRequestSubmitted()\n },\n })\n const handleMessageChange = (event: ChangeEvent<HTMLTextAreaElement>) => {\n const value = event.target.value\n setMessage(value)\n }\n\n useImperativeHandle(ref, () => {\n return {\n submit() {\n if (userProfile) {\n requestToJoinTeam({\n teamId: teamId,\n userId: userProfile.ownerId,\n message: message,\n expiresOn: undefined,\n })\n }\n },\n }\n }, [message, requestToJoinTeam, teamId, userProfile])\n\n if (status === 'pending') {\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n }}\n >\n <SynapseSpinner />\n </Box>\n )\n }\n\n if (status === 'error') {\n return <Alert severity={'error'}>{error.message}</Alert>\n }\n\n return (\n <>\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n The following message will be sent to the Team Manager(s) of the{' '}\n <strong>{team.name}</strong> team.\n </Typography>\n <Box>\n <TextField\n label={'Your Message to Team Managers(s)'}\n id=\"membershipRequestMessage\"\n value={message}\n fullWidth\n multiline\n rows={4}\n autoFocus\n onChange={handleMessageChange}\n />\n </Box>\n </>\n )\n})\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,IAAwB,EAAW,SAC9C,GACA,GACA;CACA,IAAM,EAAE,WAAQ,wBAAqB,MAAS,GACxC,CAAC,GAAS,KAAc,EAAiB,GAAG,EAE5C,EAAE,MAAM,MAAgB,GAA0B,EAElD,EACJ,MAAM,GACN,WACA,aACE,EAAW,GAAQ,EAAE,SAAS,CAAC,CAAC,GAAQ,CAAC,EAEvC,EAAE,QAAQ,MAAsB,EAAqB,EACzD,iBAAiB;AACf,KAAoB;IAEvB,CAAC;AAuCF,QAjCA,EAAoB,UACX,EACL,SAAS;AACP,EAAI,KACF,EAAkB;GACR;GACR,QAAQ,EAAY;GACX;GACT,WAAW,KAAA;GACZ,CAAC;IAGP,GACA;EAAC;EAAS;EAAmB;EAAQ;EAAY,CAAC,EAEjD,MAAW,YAEX,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;GACf,KAAK;GACN;YAED,kBAAC,GAAD,EAAkB,CAAA;EACd,CAAA,GAIN,MAAW,UACN,kBAAC,GAAD;EAAO,UAAU;YAAU,EAAM;EAAgB,CAAA,GAIxD,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,SAAQ;EAAQ,IAAI,EAAE,YAAY,QAAQ;YAAtD;GAAwD;GACW;GACjE,kBAAC,UAAD,EAAA,UAAS,EAAK,MAAc,CAAA;;GACjB;KACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,OAAO;EACP,IAAG;EACH,OAAO;EACP,WAAA;EACA,WAAA;EACA,MAAM;EACN,WAAA;EACA,WArDqB,MAA4C;GACvE,IAAM,IAAQ,EAAM,OAAO;AAC3B,KAAW,EAAM;;EAoDX,CAAA,EACE,CAAA,CACL,EAAA,CAAA;EAEL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCreateAndRegisterChallengeTeam.d.ts","sourceRoot":"","sources":["../../../src/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useCreateAndRegisterChallengeTeam.d.ts","sourceRoot":"","sources":["../../../src/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0DAA0D,CAAA;AAC7F,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,IAAI,EACL,MAAM,iCAAiC,CAAA;AAGxC;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,iCAAiC;0CAyCrC,iBAAiB,eAClB,MAAM,YACT,MAAM,EAAE,qBACC,MAAM,KACxB,OAAO,CAAC,CAAC,IAAI,EAAE,aAAa,EAAE,oBAAoB,EAAE,CAAC,CAAC;;;EA4C5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCreateAndRegisterChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"useCreateAndRegisterChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.ts"],"sourcesContent":["import {\n useCreateTeam,\n useInviteUserToTeam,\n useRegisterTeamForChallenge,\n} from '@/synapse-queries'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n ChallengeTeam,\n CreateTeamRequest,\n MembershipInvitation,\n Team,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useMemo } from 'react'\n\n/**\n * Hook that in one call will\n * - Create a team\n * - Register that team for a challenge\n * - Send invitations to join the team to a defined list of email addresses\n */\nexport default function useCreateAndRegisterChallengeTeam() {\n const {\n mutateAsync: createTeam,\n isPending: createTeamIsPending,\n error: createTeamError,\n } = useCreateTeam()\n const {\n mutateAsync: inviteUserToTeam,\n isPending: invitationIsPending,\n error: invitationError,\n } = useInviteUserToTeam()\n const {\n mutateAsync: registerTeamForChallenge,\n isPending: challengeRegistrationIsPending,\n error: challengeRegistrationError,\n } = useRegisterTeamForChallenge()\n\n // Invite the list of emails to join the team\n const handleInviteTeamMembers = useCallback(\n async (\n teamId: string,\n inviteeEmails: string[],\n invitationMessage: string,\n ) => {\n const results: MembershipInvitation[] = []\n // Send the invitations sequentially\n for (const inviteeEmail of inviteeEmails) {\n const membershipInvitation = await inviteUserToTeam({\n teamId: teamId,\n inviteeEmail: inviteeEmail.trim(),\n message: invitationMessage,\n })\n results.push(membershipInvitation)\n }\n return results\n },\n [inviteUserToTeam],\n )\n\n const createAndRegisterTeam = useCallback(\n async (\n teamToCreate: CreateTeamRequest,\n challengeId: string,\n invitees: string[],\n invitationMessage: string,\n ): Promise<[Team, ChallengeTeam, MembershipInvitation[]]> => {\n // Create the team\n const newTeam = await createTeam(teamToCreate)\n\n // Register for the challenge and invite the team members--we can do these simultaneously\n const registerPromise = registerTeamForChallenge({\n teamId: newTeam.id,\n challengeId,\n })\n const sendInvitationsPromise = handleInviteTeamMembers(\n newTeam.id,\n invitees,\n invitationMessage,\n )\n\n return Promise.all([\n Promise.resolve(newTeam),\n registerPromise,\n sendInvitationsPromise,\n ])\n },\n [createTeam, handleInviteTeamMembers, registerTeamForChallenge],\n )\n\n const errors = useMemo(() => {\n const hasError =\n createTeamError || invitationError || challengeRegistrationError\n const errors = hasError\n ? [createTeamError, invitationError, challengeRegistrationError].filter(\n (e): e is SynapseClientError => e != null,\n )\n : undefined\n\n return errors\n }, [challengeRegistrationError, createTeamError, invitationError])\n\n return {\n createAndRegisterTeam,\n isPending:\n createTeamIsPending ||\n invitationIsPending ||\n challengeRegistrationIsPending,\n errors,\n }\n}\n"],"mappings":";;;;;;AAoBA,SAAwB,IAAoC;CAC1D,IAAM,EACJ,aAAa,GACb,WAAW,GACX,OAAO,MACL,GAAe,EACb,EACJ,aAAa,GACb,WAAW,GACX,OAAO,MACL,GAAqB,EACnB,EACJ,aAAa,GACb,WAAW,GACX,OAAO,MACL,GAA6B,EAG3B,IAA0B,EAC9B,OACE,GACA,GACA,MACG;EACH,IAAM,IAAkC,EAAE;AAE1C,OAAK,IAAM,KAAgB,GAAe;GACxC,IAAM,IAAuB,MAAM,EAAiB;IAC1C;IACR,cAAc,EAAa,MAAM;IACjC,SAAS;IACV,CAAC;AACF,KAAQ,KAAK,EAAqB;;AAEpC,SAAO;IAET,CAAC,EAAiB,CACnB,EAEK,IAAwB,EAC5B,OACE,GACA,GACA,GACA,MAC2D;EAE3D,IAAM,IAAU,MAAM,EAAW,EAAa,EAGxC,IAAkB,EAAyB;GAC/C,QAAQ,EAAQ;GAChB;GACD,CAAC,EACI,IAAyB,EAC7B,EAAQ,IACR,GACA,EACD;AAED,SAAO,QAAQ,IAAI;GACjB,QAAQ,QAAQ,EAAQ;GACxB;GACA;GACD,CAAC;IAEJ;EAAC;EAAY;EAAyB;EAAyB,CAChE,EAEK,IAAS,QAEX,KAAmB,KAAmB,IAEpC;EAAC;EAAiB;EAAiB;EAA2B,CAAC,QAC5D,MAA+B,KAAK,KACtC,GACD,KAAA,GAGH;EAAC;EAA4B;EAAiB;EAAgB,CAAC;AAElE,QAAO;EACL;EACA,WACE,KACA,KACA;EACF;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateProjectModal.d.ts","sourceRoot":"","sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"names":[],"mappings":"AAgBA,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAsB,EACtB,OAAO,EACP,SAAS,GACV,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"CreateProjectModal.d.ts","sourceRoot":"","sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"names":[],"mappings":"AAgBA,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAsB,EACtB,OAAO,EACP,SAAS,GACV,EAAE,uBAAuB,2CA+MzB"}
|
|
@@ -61,20 +61,20 @@ function h({ isShowingModal: h = !1, onClose: g, gotoPlace: _ }) {
|
|
|
61
61
|
id: "projectInput",
|
|
62
62
|
label: "Project Name",
|
|
63
63
|
required: !0,
|
|
64
|
-
|
|
64
|
+
description: "Pick a unique title for your project",
|
|
65
65
|
value: y,
|
|
66
66
|
fullWidth: !0,
|
|
67
67
|
onChange: (e) => {
|
|
68
68
|
b(e.target.value);
|
|
69
69
|
},
|
|
70
|
-
|
|
70
|
+
slotProps: { htmlInput: { onKeyDown: (e) => {
|
|
71
71
|
e.key === "Enter" && y !== "" && k.mutate();
|
|
72
|
-
} }
|
|
72
|
+
} } }
|
|
73
73
|
}),
|
|
74
74
|
/* @__PURE__ */ d(a, {
|
|
75
75
|
id: "descriptionInput",
|
|
76
76
|
label: "Description",
|
|
77
|
-
|
|
77
|
+
description: "(optional)",
|
|
78
78
|
placeholder: "Brief description of this project",
|
|
79
79
|
multiline: !0,
|
|
80
80
|
minRows: 3,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateProjectModal.js","names":[],"sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Alert, Stack } from '@mui/material'\nimport { ACCESS_TYPE } from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, useState } from 'react'\nimport { useMutation } from '@tanstack/react-query'\nimport { ConfirmationDialog } from '../ConfirmationDialog/ConfirmationDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport TextField from '../TextField/TextField'\nimport {\n ProjectVisibility,\n ProjectVisibilityRadioGroup,\n} from './ProjectVisibilityRadioGroup'\n\nexport type CreateProjectModalProps = {\n isShowingModal?: boolean\n onClose: () => void\n gotoPlace?: (href: string) => void\n}\n\nexport function CreateProjectModal({\n isShowingModal = false,\n onClose,\n gotoPlace,\n}: CreateProjectModalProps) {\n const { accessToken } = useSynapseContext()\n const [projectName, setProjectName] = useState<string>('')\n const [description, setDescription] = useState<string>('')\n const [visibility, setVisibility] =\n useState<ProjectVisibility>('DISCOVERABLE')\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const publicGroupId = realmPrincipals?.publicGroup\n const authenticatedUsersId = realmPrincipals?.authenticatedUsers\n\n const applyVisibilityAcl = async (projectId: string): Promise<void> => {\n if (visibility === 'PRIVATE') {\n return\n }\n try {\n const currentAcl = await SynapseClient.getEntityACL(\n projectId,\n accessToken,\n )\n\n const upsertAccessTypes = (\n entries: typeof currentAcl.resourceAccess,\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ): typeof currentAcl.resourceAccess => {\n const existing = entries.find(e => e.principalId === principalId)\n if (existing) {\n return entries.map(e =>\n e.principalId === principalId\n ? {\n ...e,\n accessType: [...new Set([...e.accessType, ...accessTypes])],\n }\n : e,\n )\n }\n return [...entries, { principalId, accessType: accessTypes }]\n }\n\n let newResourceAccess = [...currentAcl.resourceAccess]\n\n if (visibility === 'DISCOVERABLE') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ],\n )\n }\n } else if (visibility === 'PUBLIC') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ, ACCESS_TYPE.DOWNLOAD],\n )\n }\n }\n\n await SynapseClient.updateEntityACL(\n { ...currentAcl, resourceAccess: newResourceAccess },\n accessToken,\n )\n } catch (e) {\n const err = e as SynapseClientError\n throw new Error(\n `Project was created, but visibility could not be set: ${\n err.reason ?? err.message\n }`,\n )\n }\n }\n\n const createProjectMutation = useMutation({\n mutationFn: async () => {\n const newProject = await SynapseClient.createProject(\n projectName,\n description,\n accessToken,\n )\n let aclError: string | undefined\n try {\n await applyVisibilityAcl(newProject.id!)\n } catch (e) {\n aclError = (e as Error).message\n }\n return { newProject, aclError }\n },\n onError: error => {\n const synapseError = error as SynapseClientError\n displayToast(synapseError.reason ?? error.message, 'danger')\n },\n onSuccess: ({ newProject, aclError }) => {\n // Note - Do NOT call createProjectMutation.reset() here — in TanStack Query v5,\n // reset() inside onSuccess interrupts the rest of this callback.\n // Note 2 - displayToast is not shown in Storybook (with the window.location.href change), but works when\n // integrated in the Synapse.org app.\n if (aclError) {\n displayToast(aclError, 'danger')\n } else {\n displayToast('Project created', 'success')\n }\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n onClose()\n const href = `/Synapse:${newProject.id}`\n if (gotoPlace) {\n gotoPlace(href)\n } else {\n window.location.href = href\n }\n },\n })\n\n const hide = () => {\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n createProjectMutation.reset()\n onClose()\n }\n\n const dialogContent = (\n <Stack gap={2}>\n <TextField\n id=\"projectInput\"\n label=\"Project Name\"\n required\n
|
|
1
|
+
{"version":3,"file":"CreateProjectModal.js","names":[],"sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Alert, Stack } from '@mui/material'\nimport { ACCESS_TYPE } from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, useState } from 'react'\nimport { useMutation } from '@tanstack/react-query'\nimport { ConfirmationDialog } from '../ConfirmationDialog/ConfirmationDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport TextField from '../TextField/TextField'\nimport {\n ProjectVisibility,\n ProjectVisibilityRadioGroup,\n} from './ProjectVisibilityRadioGroup'\n\nexport type CreateProjectModalProps = {\n isShowingModal?: boolean\n onClose: () => void\n gotoPlace?: (href: string) => void\n}\n\nexport function CreateProjectModal({\n isShowingModal = false,\n onClose,\n gotoPlace,\n}: CreateProjectModalProps) {\n const { accessToken } = useSynapseContext()\n const [projectName, setProjectName] = useState<string>('')\n const [description, setDescription] = useState<string>('')\n const [visibility, setVisibility] =\n useState<ProjectVisibility>('DISCOVERABLE')\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const publicGroupId = realmPrincipals?.publicGroup\n const authenticatedUsersId = realmPrincipals?.authenticatedUsers\n\n const applyVisibilityAcl = async (projectId: string): Promise<void> => {\n if (visibility === 'PRIVATE') {\n return\n }\n try {\n const currentAcl = await SynapseClient.getEntityACL(\n projectId,\n accessToken,\n )\n\n const upsertAccessTypes = (\n entries: typeof currentAcl.resourceAccess,\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ): typeof currentAcl.resourceAccess => {\n const existing = entries.find(e => e.principalId === principalId)\n if (existing) {\n return entries.map(e =>\n e.principalId === principalId\n ? {\n ...e,\n accessType: [...new Set([...e.accessType, ...accessTypes])],\n }\n : e,\n )\n }\n return [...entries, { principalId, accessType: accessTypes }]\n }\n\n let newResourceAccess = [...currentAcl.resourceAccess]\n\n if (visibility === 'DISCOVERABLE') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ],\n )\n }\n } else if (visibility === 'PUBLIC') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ, ACCESS_TYPE.DOWNLOAD],\n )\n }\n }\n\n await SynapseClient.updateEntityACL(\n { ...currentAcl, resourceAccess: newResourceAccess },\n accessToken,\n )\n } catch (e) {\n const err = e as SynapseClientError\n throw new Error(\n `Project was created, but visibility could not be set: ${\n err.reason ?? err.message\n }`,\n )\n }\n }\n\n const createProjectMutation = useMutation({\n mutationFn: async () => {\n const newProject = await SynapseClient.createProject(\n projectName,\n description,\n accessToken,\n )\n let aclError: string | undefined\n try {\n await applyVisibilityAcl(newProject.id!)\n } catch (e) {\n aclError = (e as Error).message\n }\n return { newProject, aclError }\n },\n onError: error => {\n const synapseError = error as SynapseClientError\n displayToast(synapseError.reason ?? error.message, 'danger')\n },\n onSuccess: ({ newProject, aclError }) => {\n // Note - Do NOT call createProjectMutation.reset() here — in TanStack Query v5,\n // reset() inside onSuccess interrupts the rest of this callback.\n // Note 2 - displayToast is not shown in Storybook (with the window.location.href change), but works when\n // integrated in the Synapse.org app.\n if (aclError) {\n displayToast(aclError, 'danger')\n } else {\n displayToast('Project created', 'success')\n }\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n onClose()\n const href = `/Synapse:${newProject.id}`\n if (gotoPlace) {\n gotoPlace(href)\n } else {\n window.location.href = href\n }\n },\n })\n\n const hide = () => {\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n createProjectMutation.reset()\n onClose()\n }\n\n const dialogContent = (\n <Stack gap={2}>\n <TextField\n id=\"projectInput\"\n label=\"Project Name\"\n required\n description=\"Pick a unique title for your project\"\n value={projectName}\n fullWidth\n onChange={event => {\n setProjectName(event.target.value)\n }}\n slotProps={{\n htmlInput: {\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if (projectName !== '') {\n createProjectMutation.mutate()\n }\n }\n },\n },\n }}\n />\n <TextField\n id=\"descriptionInput\"\n label=\"Description\"\n description=\"(optional)\"\n placeholder=\"Brief description of this project\"\n multiline\n minRows={3}\n value={description}\n fullWidth\n maxCharacterCount={350}\n onChange={event => {\n setDescription(event.target.value)\n }}\n />\n <ProjectVisibilityRadioGroup\n value={visibility}\n onChange={setVisibility}\n />\n <Alert severity=\"warning\">\n You can update project visibility at any time in Project Tools, or\n manage access at a more granular level for individual files and folders.\n </Alert>\n </Stack>\n )\n\n return (\n <>\n <ConfirmationDialog\n open={isShowingModal}\n title=\"Create a new Project\"\n content={dialogContent}\n confirmButtonProps={{\n children: 'Save',\n disabled: createProjectMutation.isPending,\n loading: createProjectMutation.isPending,\n }}\n onConfirm={() => {\n createProjectMutation.mutate()\n }}\n onCancel={hide}\n maxWidth=\"sm\"\n dense\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useGetFeatureFlag as e } from "../../synapse-queries/featureflags/useGetFeatureFlag.js";
|
|
2
2
|
import "../../synapse-queries/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { FeatureFlagEnum as t } from "../../utils/featureflag/FeatureFlags.js";
|
|
4
|
+
import { TextField as n } from "@mui/material";
|
|
5
|
+
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/CreateTableViewWizard/TableNameForm.tsx
|
|
7
7
|
function o(o) {
|
|
8
|
-
let { name: s, setName: c, description: l, setDescription: u } = o, d = e(
|
|
9
|
-
return /* @__PURE__ */
|
|
8
|
+
let { name: s, setName: c, description: l, setDescription: u } = o, d = e(t.DESCRIPTION_FIELD);
|
|
9
|
+
return /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i(n, {
|
|
10
10
|
required: !0,
|
|
11
11
|
label: "Name",
|
|
12
12
|
value: s,
|
|
@@ -14,7 +14,7 @@ function o(o) {
|
|
|
14
14
|
c(e.target.value);
|
|
15
15
|
},
|
|
16
16
|
fullWidth: !0
|
|
17
|
-
}), d && /* @__PURE__ */
|
|
17
|
+
}), d && /* @__PURE__ */ i(n, {
|
|
18
18
|
label: "Description",
|
|
19
19
|
value: l,
|
|
20
20
|
onChange: (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableNameForm.js","names":[],"sources":["../../../src/components/CreateTableViewWizard/TableNameForm.tsx"],"sourcesContent":["import { useGetFeatureFlag } from '@/synapse-queries'\nimport { TextField } from '@mui/material'\nimport { FeatureFlagEnum } from '
|
|
1
|
+
{"version":3,"file":"TableNameForm.js","names":[],"sources":["../../../src/components/CreateTableViewWizard/TableNameForm.tsx"],"sourcesContent":["import { useGetFeatureFlag } from '@/synapse-queries'\nimport { TextField } from '@mui/material'\nimport { FeatureFlagEnum } from '@/utils/featureflag/FeatureFlags'\nimport { Dispatch, SetStateAction } from 'react'\n\ntype TableNameFormProps = {\n name: string\n setName: Dispatch<SetStateAction<string>>\n description: string | undefined\n setDescription: Dispatch<SetStateAction<string | undefined>>\n}\n\n/**\n * React component for the naming a new table or view.\n * Renders UI to provide the name and description of a table or view.\n */\nexport default function TableNameForm(props: TableNameFormProps) {\n const { name, setName, description, setDescription } = props\n const isFeatureEnabled = useGetFeatureFlag(FeatureFlagEnum.DESCRIPTION_FIELD)\n return (\n <>\n <TextField\n required\n label={'Name'}\n value={name}\n onChange={e => {\n setName(e.target.value)\n }}\n fullWidth\n />\n {isFeatureEnabled && (\n <TextField\n label={'Description'}\n value={description}\n onChange={e => {\n setDescription(e.target.value || undefined)\n }}\n fullWidth\n multiline\n rows={3}\n sx={{ my: 2 }}\n />\n )}\n </>\n )\n}\n"],"mappings":";;;;;;AAgBA,SAAwB,EAAc,GAA2B;CAC/D,IAAM,EAAE,SAAM,YAAS,gBAAa,sBAAmB,GACjD,IAAmB,EAAkB,EAAgB,kBAAkB;AAC7E,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,UAAA;EACA,OAAO;EACP,OAAO;EACP,WAAU,MAAK;AACb,KAAQ,EAAE,OAAO,MAAM;;EAEzB,WAAA;EACA,CAAA,EACD,KACC,kBAAC,GAAD;EACE,OAAO;EACP,OAAO;EACP,WAAU,MAAK;AACb,KAAe,EAAE,OAAO,SAAS,KAAA,EAAU;;EAE7C,WAAA;EACA,WAAA;EACA,MAAM;EACN,IAAI,EAAE,IAAI,GAAG;EACb,CAAA,CAEH,EAAA,CAAA"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useGetFeatureFlag as e } from "../../synapse-queries/featureflags/useGetFeatureFlag.js";
|
|
2
2
|
import "../../synapse-queries/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { FeatureFlagEnum as t } from "../../utils/featureflag/FeatureFlags.js";
|
|
4
|
+
import { useEffect as n } from "react";
|
|
5
5
|
//#region src/components/CrispChat/CrispChat.tsx
|
|
6
6
|
var r = !1;
|
|
7
7
|
function i() {
|
|
8
|
-
let i = e(
|
|
9
|
-
return
|
|
8
|
+
let i = e(t.CRISP_CHAT);
|
|
9
|
+
return n(() => {
|
|
10
10
|
if (i && !r) {
|
|
11
11
|
window.$crisp = window.$crisp || [], window.CRISP_WEBSITE_ID = "c9bf8451-61b5-4b7e-b564-5772f85d54bd";
|
|
12
12
|
let e = document.createElement("script");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrispChat.js","names":[],"sources":["../../../src/components/CrispChat/CrispChat.tsx"],"sourcesContent":["import './CrispTypes'\nimport React, { useEffect } from 'react'\nimport { FeatureFlagEnum } from '
|
|
1
|
+
{"version":3,"file":"CrispChat.js","names":[],"sources":["../../../src/components/CrispChat/CrispChat.tsx"],"sourcesContent":["import './CrispTypes'\nimport React, { useEffect } from 'react'\nimport { FeatureFlagEnum } from '@/utils/featureflag/FeatureFlags'\nimport { useGetFeatureFlag } from '@/synapse-queries'\n\n// Ensure script is only loaded once\nlet isScriptLoaded = false\n\n/**\n * CrispChat component that loads the Crisp chat widget when the CRISP_CHAT feature flag is enabled.\n * The script is only loaded once, even if the component is mounted multiple times.\n */\nexport function CrispChat(): React.ReactNode {\n const isCrispChatEnabled = useGetFeatureFlag(FeatureFlagEnum.CRISP_CHAT)\n\n useEffect(() => {\n if (isCrispChatEnabled && !isScriptLoaded) {\n // Initialize Crisp\n window.$crisp = window.$crisp || []\n window.CRISP_WEBSITE_ID = 'c9bf8451-61b5-4b7e-b564-5772f85d54bd'\n\n // Create and append the script\n const script = document.createElement('script')\n script.type = 'text/javascript'\n script.src = 'https://client.crisp.chat/l.js'\n script.async = true\n\n const target = document.head ?? document.body\n target?.appendChild(script)\n\n isScriptLoaded = true\n }\n }, [isCrispChatEnabled])\n\n return null\n}\n\nexport default CrispChat\n"],"mappings":";;;;;AAMA,IAAI,IAAiB;AAMrB,SAAgB,IAA6B;CAC3C,IAAM,IAAqB,EAAkB,EAAgB,WAAW;AAqBxE,QAnBA,QAAgB;AACd,MAAI,KAAsB,CAAC,GAAgB;AAGzC,GADA,OAAO,SAAS,OAAO,UAAU,EAAE,EACnC,OAAO,mBAAmB;GAG1B,IAAM,IAAS,SAAS,cAAc,SAAS;AAQ/C,GAPA,EAAO,OAAO,mBACd,EAAO,MAAM,kCACb,EAAO,QAAQ,KAEA,SAAS,QAAQ,SAAS,OACjC,YAAY,EAAO,EAE3B,IAAiB;;IAElB,CAAC,EAAmB,CAAC,EAEjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRxResponseComplete.js","names":["JsonRxMessage","RESPONSE_COMPLETE_TYPE_CODE","JsonRxResponseComplete","subscriptionId","payload","TPayload","getSubscriptionId","getPayload","constructor","getJson","Array","json","typeCode","undefined","push"],"sources":["../../../../../src/components/DataGrid/utils/json-rx/JsonRxResponseComplete.ts"],"sourcesContent":["import JsonRxMessage from './JsonRxMessage'\n\nexport const RESPONSE_COMPLETE_TYPE_CODE = 5\n\nexport default class JsonRxResponseComplete<\n TPayload = unknown,\n> extends JsonRxMessage {\n private subscriptionId: number\n private payload?: TPayload\n\n public getSubscriptionId(): number {\n return this.subscriptionId\n }\n\n public getPayload(): TPayload | undefined {\n return this.payload
|
|
1
|
+
{"version":3,"file":"JsonRxResponseComplete.js","names":["JsonRxMessage","RESPONSE_COMPLETE_TYPE_CODE","JsonRxResponseComplete","subscriptionId","payload","TPayload","getSubscriptionId","getPayload","constructor","getJson","Array","json","typeCode","undefined","push"],"sources":["../../../../../src/components/DataGrid/utils/json-rx/JsonRxResponseComplete.ts"],"sourcesContent":["import JsonRxMessage from './JsonRxMessage'\n\nexport const RESPONSE_COMPLETE_TYPE_CODE = 5\n\nexport default class JsonRxResponseComplete<\n TPayload = unknown,\n> extends JsonRxMessage {\n private subscriptionId: number\n private payload?: TPayload\n\n public getSubscriptionId(): number {\n return this.subscriptionId\n }\n\n public getPayload(): TPayload | undefined {\n return this.payload\n }\n constructor(subscriptionId: number, payload?: TPayload) {\n super(RESPONSE_COMPLETE_TYPE_CODE)\n this.subscriptionId = subscriptionId\n this.payload = payload\n }\n\n public getJson(): Array<unknown> {\n const json: Array<unknown> = [this.typeCode, this.subscriptionId]\n if (this.payload !== undefined) {\n json.push(this.payload)\n }\n return json\n }\n}\n"],"mappings":";;AAEA,IAAaC,IAA8B,GAEtBC,IAArB,cAEUF,EAAc;CACtB;CACA;CAEA,oBAAmC;AACjC,SAAO,KAAKG;;CAGd,aAA0C;AACxC,SAAO,KAAKC;;CAEdI,YAAYL,GAAwBC,GAAoB;AAGtD,EAFA,MAAA,EAAkC,EAClC,KAAKD,iBAAiBA,GACtB,KAAKC,UAAUA;;CAGjB,UAAiC;EAC/B,IAAMO,IAAuB,CAAC,KAAKC,UAAU,KAAKT,eAAe;AAIjE,SAHI,KAAKC,YAAYS,KAAAA,KACnBF,EAAKG,KAAK,KAAKV,QAAQ,EAElBO"}
|
|
@@ -3,34 +3,34 @@ import t from "../../synapse-queries/entity/useEntityBundle.js";
|
|
|
3
3
|
import { useGetFeatureFlag as n } from "../../synapse-queries/featureflags/useGetFeatureFlag.js";
|
|
4
4
|
import "../../synapse-queries/index.js";
|
|
5
5
|
import { ActionRequiredCard as r } from "./ActionRequiredCard/ActionRequiredCard.js";
|
|
6
|
-
import i from "
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { FeatureFlagEnum as i } from "../../utils/featureflag/FeatureFlags.js";
|
|
7
|
+
import a from "../EntityAclEditor/EntityAclEditorModal.js";
|
|
8
|
+
import { useState as o } from "react";
|
|
9
|
+
import { Alert as s, Button as c, Typography as l } from "@mui/material";
|
|
10
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
11
11
|
//#region src/components/DownloadCart/RequestDownloadCard.tsx
|
|
12
12
|
var p = ((e) => window.open(`https://www.synapse.org/Synapse:${e}`, "_blank")), m = "Download Permission Required";
|
|
13
13
|
function h(h) {
|
|
14
14
|
let { entityId: g, count: _, onViewSharingSettingsClicked: v = p } = h, { data: y, isLoading: b, isError: x, error: S } = t(g, void 0, {
|
|
15
15
|
includeEntity: !0,
|
|
16
16
|
includePermissions: !0
|
|
17
|
-
}), [C, w] =
|
|
18
|
-
return x ? /* @__PURE__ */
|
|
17
|
+
}), [C, w] = o(!1), T = !!y?.permissions.canDownload, E = n(i.REACT_ENTITY_ACL_EDITOR);
|
|
18
|
+
return x ? /* @__PURE__ */ d(s, {
|
|
19
19
|
severity: "error",
|
|
20
20
|
children: S.reason
|
|
21
|
-
}) : /* @__PURE__ */
|
|
21
|
+
}) : /* @__PURE__ */ d(r, {
|
|
22
22
|
isLoading: b,
|
|
23
23
|
title: m,
|
|
24
|
-
description: /* @__PURE__ */
|
|
24
|
+
description: /* @__PURE__ */ f(u, { children: [
|
|
25
25
|
"You must be granted the download permission on",
|
|
26
26
|
" ",
|
|
27
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ d("strong", { children: y?.entity.name }),
|
|
28
28
|
" in order to download this set of files."
|
|
29
29
|
] }),
|
|
30
30
|
iconType: e,
|
|
31
31
|
count: _,
|
|
32
|
-
actionNode: /* @__PURE__ */
|
|
33
|
-
/* @__PURE__ */
|
|
32
|
+
actionNode: /* @__PURE__ */ f(u, { children: [
|
|
33
|
+
/* @__PURE__ */ d(l, {
|
|
34
34
|
variant: "smallText1",
|
|
35
35
|
sx: {
|
|
36
36
|
mb: 1,
|
|
@@ -38,12 +38,12 @@ function h(h) {
|
|
|
38
38
|
},
|
|
39
39
|
children: "Contact an administrator to request download permission"
|
|
40
40
|
}),
|
|
41
|
-
/* @__PURE__ */
|
|
41
|
+
/* @__PURE__ */ d(a, {
|
|
42
42
|
entityId: g,
|
|
43
43
|
open: C,
|
|
44
44
|
onClose: () => w(!1)
|
|
45
45
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
46
|
+
/* @__PURE__ */ d(c, {
|
|
47
47
|
variant: "outlined",
|
|
48
48
|
onClick: () => {
|
|
49
49
|
E ? w(!0) : v(g);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestDownloadCard.js","names":[],"sources":["../../../src/components/DownloadCart/RequestDownloadCard.tsx"],"sourcesContent":["import { useGetEntityBundle, useGetFeatureFlag } from '@/synapse-queries'\nimport { DOWNLOAD_PERMISSION_REQUIRED } from '@/utils/SynapseConstants'\nimport { Alert, Button, Typography } from '@mui/material'\nimport { FeatureFlagEnum } from '
|
|
1
|
+
{"version":3,"file":"RequestDownloadCard.js","names":[],"sources":["../../../src/components/DownloadCart/RequestDownloadCard.tsx"],"sourcesContent":["import { useGetEntityBundle, useGetFeatureFlag } from '@/synapse-queries'\nimport { DOWNLOAD_PERMISSION_REQUIRED } from '@/utils/SynapseConstants'\nimport { Alert, Button, Typography } from '@mui/material'\nimport { FeatureFlagEnum } from '@/utils/featureflag/FeatureFlags'\nimport { useState } from 'react'\nimport EntityAclEditorModal from '../EntityAclEditor/EntityAclEditorModal'\nimport { ActionRequiredCard } from './ActionRequiredCard/ActionRequiredCard'\n\nexport type RequestDownloadCardProps = {\n entityId: string\n count?: number\n /** Invoked when a user clicks \"View Sharing Settings\" for a set of files that require the Download permission*/\n onViewSharingSettingsClicked?: (benefactorId: string) => void\n}\n\nconst DEFAULT_ON_VIEW_SHARING_SETTINGS_CLICKED = (benefactorEntityId =>\n window.open(\n `https://www.synapse.org/Synapse:${benefactorEntityId}`,\n '_blank',\n )) satisfies RequestDownloadCardProps['onViewSharingSettingsClicked']\n\nexport const REQUEST_DOWNLOAD_TITLE = 'Download Permission Required'\nexport function RequestDownloadCard(props: RequestDownloadCardProps) {\n const {\n entityId,\n count,\n onViewSharingSettingsClicked = DEFAULT_ON_VIEW_SHARING_SETTINGS_CLICKED,\n } = props\n const {\n data: entityBundle,\n isLoading,\n isError,\n error,\n } = useGetEntityBundle(entityId, undefined, {\n includeEntity: true,\n includePermissions: true,\n })\n\n const [showSharingSettings, setShowSharingSettings] = useState(false)\n\n const hasDownloadPermission = Boolean(entityBundle?.permissions.canDownload)\n\n const useReactACLEditor = useGetFeatureFlag(\n FeatureFlagEnum.REACT_ENTITY_ACL_EDITOR,\n )\n\n if (isError) {\n return <Alert severity={'error'}>{error.reason}</Alert>\n }\n return (\n <ActionRequiredCard\n isLoading={isLoading}\n title={REQUEST_DOWNLOAD_TITLE}\n description={\n <>\n You must be granted the download permission on{' '}\n <strong>{entityBundle?.entity.name}</strong> in order to download this\n set of files.\n </>\n }\n iconType={DOWNLOAD_PERMISSION_REQUIRED}\n count={count}\n actionNode={\n <>\n <Typography variant=\"smallText1\" sx={{ mb: 1, color: 'grey.700' }}>\n Contact an administrator to request download permission\n </Typography>\n <EntityAclEditorModal\n entityId={entityId}\n open={showSharingSettings}\n onClose={() => setShowSharingSettings(false)}\n />\n <Button\n variant=\"outlined\"\n onClick={() => {\n if (useReactACLEditor) {\n setShowSharingSettings(true)\n } else {\n onViewSharingSettingsClicked(entityId)\n }\n }}\n disabled={hasDownloadPermission}\n >\n {hasDownloadPermission ? 'Complete' : 'View Sharing Settings'}\n </Button>\n </>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAM,MAA4C,MAChD,OAAO,KACL,mCAAmC,KACnC,SACD,GAEU,IAAyB;AACtC,SAAgB,EAAoB,GAAiC;CACnE,IAAM,EACJ,aACA,UACA,kCAA+B,MAC7B,GACE,EACJ,MAAM,GACN,cACA,YACA,aACE,EAAmB,GAAU,KAAA,GAAW;EAC1C,eAAe;EACf,oBAAoB;EACrB,CAAC,EAEI,CAAC,GAAqB,KAA0B,EAAS,GAAM,EAE/D,IAAwB,EAAQ,GAAc,YAAY,aAE1D,IAAoB,EACxB,EAAgB,wBACjB;AAKD,QAHI,IACK,kBAAC,GAAD;EAAO,UAAU;YAAU,EAAM;EAAe,CAAA,GAGvD,kBAAC,GAAD;EACa;EACX,OAAO;EACP,aACE,kBAAA,GAAA,EAAA,UAAA;GAAE;GAC+C;GAC/C,kBAAC,UAAD,EAAA,UAAS,GAAc,OAAO,MAAc,CAAA;;GAE3C,EAAA,CAAA;EAEL,UAAU;EACH;EACP,YACE,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,GAAD;IAAY,SAAQ;IAAa,IAAI;KAAE,IAAI;KAAG,OAAO;KAAY;cAAE;IAEtD,CAAA;GACb,kBAAC,GAAD;IACY;IACV,MAAM;IACN,eAAe,EAAuB,GAAM;IAC5C,CAAA;GACF,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe;AACb,KAAI,IACF,EAAuB,GAAK,GAE5B,EAA6B,EAAS;;IAG1C,UAAU;cAET,IAAwB,aAAa;IAC/B,CAAA;GACR,EAAA,CAAA;EAEL,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityAclEditor.d.ts","sourceRoot":"","sources":["../../../src/components/EntityAclEditor/EntityAclEditor.tsx"],"names":[],"mappings":"AAyDA,MAAM,MAAM,oBAAoB,GAAG;IACjC,oIAAoI;IACpI,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,eAAe,EAAE,CAAC,cAAc,EAAE,OAAO,KAAK,IAAI,CAAA;IAClD,kDAAkD;IAClD,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B;;6BAEyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;
|
|
1
|
+
{"version":3,"file":"EntityAclEditor.d.ts","sourceRoot":"","sources":["../../../src/components/EntityAclEditor/EntityAclEditor.tsx"],"names":[],"mappings":"AAyDA,MAAM,MAAM,oBAAoB,GAAG;IACjC,oIAAoI;IACpI,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,eAAe,EAAE,CAAC,cAAc,EAAE,OAAO,KAAK,IAAI,CAAA;IAClD,kDAAkD;IAClD,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B;;6BAEyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAgYD,QAAA,MAAM,2BAA2B,wHAahC,CAAA;AAED,eAAe,2BAA2B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityAclEditor.js","names":[],"sources":["../../../src/components/EntityAclEditor/EntityAclEditor.tsx"],"sourcesContent":["import {\n useCreateEntityACL,\n useDeleteEntityACL,\n useSuspenseGetCurrentUserProfile,\n useSuspenseGetEntityBenefactorACL,\n useSuspenseGetEntityBundle,\n useUpdateEntityACL,\n} from '@/synapse-queries'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { BackendDestinationEnum, getEndpoint } from '@/utils/functions'\nimport {\n consolidateResourceAccessList,\n isEntityPublic,\n resourceAccessListIsEqual,\n} from '@/utils/functions/AccessControlListUtils'\nimport { getPrincipalDisplayName } from '@/utils/functions/getPrincipalDisplayName'\nimport { entityTypeToFriendlyName } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAccessTypeFromPermissionLevel,\n PermissionLevel,\n permissionLevelToLabel,\n} from '@/utils/PermissionLevelToAccessType'\nimport { SYNAPSE_DOCS_SHARING_SETTINGS_PERMISSIONS_CONDITIONS_FOR_USE_URL } from '@/utils/SynapseConstants'\nimport { Alert, Link, Stack } from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n ALL_ENTITY_BUNDLE_FIELDS,\n ResourceAccess,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n Suspense,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { AclEditor, AclEditorProps } from '../AclEditor/AclEditor'\nimport { AclEditorSkeleton } from '../AclEditor/AclEditorSkeleton'\nimport useUpdateAcl from '../AclEditor/useUpdateAcl'\nimport { SynapseErrorBoundary } from '../error'\nimport FullWidthAlert from '../FullWidthAlert'\nimport { CreateOrDeleteLocalSharingSettingsButton } from './CreateOrDeleteLocalSharingSettingsButton'\nimport { InheritanceMessage } from './InheritanceMessage'\nimport OpenData from './OpenData'\nimport useNotifyNewACLUsers from './useNotifyNewACLUsers'\n\nconst availablePermissionLevels: PermissionLevel[] = [\n 'CAN_VIEW',\n 'CAN_DOWNLOAD',\n 'CAN_EDIT',\n 'CAN_EDIT_DELETE',\n 'CAN_ADMINISTER',\n]\n\nexport type EntityAclEditorProps = {\n /** The ID of the entity on which to view/edit the ACL. Note that the ACL may actually belong to an entity ancestor (benefactor). */\n entityId: string\n /** Invoked when the user can/cannot save the pending changes. */\n onCanSaveChange: (canSaveChanges: boolean) => void\n /** Invoked when changes are successfully made. */\n onUpdateSuccess: () => void\n /** Special case to show specific copy and allow changes to an inherited ACL immediately after a file is uploaded.\n * Note that if this is true, the entityId should be the ID of the folder or project that is the benefactor of the newly uploaded file(s)\n * @defaultValue false */\n isAfterUpload?: boolean\n}\n\nexport type EntityAclEditorHandle = {\n save: () => void\n}\n\nfunction getSubject(entityName: string) {\n return `${entityName} (shared on Synapse)`\n}\n\nfunction getBody(profile: UserProfile, entityId: string) {\n return `${getPrincipalDisplayName(\n {\n userName: profile.userName ?? '',\n firstName: profile.firstName,\n lastName: profile.lastName,\n },\n { showFullName: true, showUsername: false },\n )} has shared an item with you on Synapse:\\n${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${entityId}`\n}\n\nfunction getCanEditResourceAccess(\n canEdit: boolean,\n isInherited: boolean,\n ownProfile: UserProfile,\n publicGroupId: string | undefined,\n): AclEditorProps['canEdit'] {\n if (!canEdit || isInherited) {\n return false\n }\n return (resourceAccess: ResourceAccess): boolean => {\n // Users cannot change their own permissions\n const isSelf = ownProfile.ownerId === String(resourceAccess.principalId)\n // Users cannot change permission level for the public group, only add/remove it.\n // To give the public group DOWNLOAD access, ACT must mark it as anonymous access.\n const isPublicGroup =\n publicGroupId !== undefined &&\n String(resourceAccess.principalId) === publicGroupId\n if (isSelf || isPublicGroup) {\n return false\n }\n return true\n }\n}\n\nfunction getCanDeleteResourceAccess(\n canEdit: boolean,\n isInherited: boolean,\n ownProfile: UserProfile,\n): AclEditorProps['canRemoveEntry'] {\n if (!canEdit || isInherited) {\n return false\n }\n return (resourceAccess: ResourceAccess): boolean => {\n // Users cannot delete their own permissions\n const isSelf = ownProfile.ownerId === String(resourceAccess.principalId)\n if (isSelf) {\n return false\n }\n return canEdit\n }\n}\n\nfunction getDisplayedPermissionLevelOverride(\n isOpenData: boolean,\n publicGroupId: string | undefined,\n): AclEditorProps['displayedPermissionLevelOverride'] {\n return (resourceAccess: ResourceAccess) => {\n if (\n publicGroupId !== undefined &&\n String(resourceAccess.principalId) === publicGroupId\n ) {\n return isOpenData\n ? permissionLevelToLabel['CAN_DOWNLOAD']\n : permissionLevelToLabel['CAN_VIEW']\n }\n return undefined\n }\n}\n\nconst EntityAclEditor = forwardRef(function EntityAclEditor(\n props: EntityAclEditorProps,\n ref: ForwardedRef<EntityAclEditorHandle>,\n) {\n const {\n entityId,\n onCanSaveChange,\n onUpdateSuccess,\n isAfterUpload = false,\n } = props\n\n const { data: ownProfile } = useSuspenseGetCurrentUserProfile()\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const { publicGroup: publicGroupId } = realmPrincipals || {}\n const { data: entityBundle } = useSuspenseGetEntityBundle(\n entityId,\n undefined,\n ALL_ENTITY_BUNDLE_FIELDS,\n { staleTime: Infinity },\n )\n const isProject = EntityType.project == entityBundle.entityType\n\n // The parent's benefactor ACL will be shown if the user removes the ACL on the current entity\n const { data: parentAcl } = useSuspenseGetEntityBenefactorACL(\n entityBundle.entity.parentId!,\n {\n staleTime: Infinity,\n },\n )\n\n const consolidatedOriginalResourceAccess = useMemo(\n () =>\n consolidateResourceAccessList(entityBundle.benefactorAcl.resourceAccess),\n [entityBundle.benefactorAcl.resourceAccess],\n )\n\n const parentResourceAccess = useMemo(\n () => parentAcl?.resourceAccess ?? [],\n [parentAcl],\n )\n const canEdit = entityBundle.permissions.canChangePermissions\n const isOpenData = entityBundle.permissions.isEntityOpenData\n const originalIsInherited = !(entityBundle.benefactorAcl.id == entityId)\n const [updatedIsInherited, setUpdatedIsInherited] =\n useState(originalIsInherited)\n const [notifyNewAdditions, setNotifyNewAdditions] = useState(false)\n const [error, setError] = useState<Error>()\n\n const {\n resourceAccessList: updatedResourceAccessList,\n setResourceAccessList,\n addResourceAccessItem,\n updateResourceAccessItem,\n removeResourceAccessItem,\n resetDirtyState,\n } = useUpdateAcl({\n initialResourceAccessList: consolidatedOriginalResourceAccess,\n })\n\n // If `consolidatedOriginalResourceAccess` changes, reset state\n useEffect(() => {\n if (consolidatedOriginalResourceAccess) {\n resetDirtyState()\n setResourceAccessList([...consolidatedOriginalResourceAccess])\n }\n }, [\n consolidatedOriginalResourceAccess,\n resetDirtyState,\n setResourceAccessList,\n ])\n\n // If `originalIsInherited` changes, reset state\n useEffect(() => {\n resetDirtyState()\n setUpdatedIsInherited(originalIsInherited)\n }, [originalIsInherited, resetDirtyState])\n\n // If the editor toggles the inherited state, reset the resource access list\n useEffect(() => {\n if (originalIsInherited == updatedIsInherited) {\n // The user reverted to the original state (regardless of inherited or not)\n setResourceAccessList(consolidatedOriginalResourceAccess)\n } else if (updatedIsInherited) {\n // The user toggled to inherited, update the resource access list to match the parent\n setResourceAccessList(parentResourceAccess)\n } else {\n // The user toggled to local, no need to update the list (the parent's list is already in the editor)\n }\n resetDirtyState()\n }, [\n originalIsInherited,\n consolidatedOriginalResourceAccess,\n parentResourceAccess,\n resetDirtyState,\n setResourceAccessList,\n updatedIsInherited,\n ])\n\n const isPublic = isEntityPublic(\n updatedResourceAccessList,\n realmPrincipals ?? {},\n )\n\n const {\n sendNotification,\n isLoading: isLoadingSendMessageToNewACLUsers,\n isPending: isPendingSendMessageToNewACLUsers,\n } = useNotifyNewACLUsers({\n subject: getSubject(entityBundle.entity.name || ''),\n body: getBody(ownProfile, entityId),\n initialResourceAccessList: consolidatedOriginalResourceAccess,\n newResourceAccessList: updatedResourceAccessList,\n })\n\n const mutationOptions = {\n onSuccess: () => {\n if (notifyNewAdditions) {\n sendNotification()\n }\n onUpdateSuccess()\n },\n onError: (e: Error) => {\n setError(e)\n },\n }\n\n const { mutate: createAcl, isPending: isPendingCreateAcl } =\n useCreateEntityACL(mutationOptions)\n const { mutate: updateAcl, isPending: isPendingUpdateAcl } =\n useUpdateEntityACL(mutationOptions)\n const { mutate: deleteAcl, isPending: isPendingDeleteAcl } =\n useDeleteEntityACL(mutationOptions)\n\n const isPending =\n isPendingCreateAcl ||\n isPendingUpdateAcl ||\n isPendingDeleteAcl ||\n isPendingSendMessageToNewACLUsers\n\n const hasAclChanged = useMemo(() => {\n return (\n originalIsInherited != updatedIsInherited ||\n !resourceAccessListIsEqual(\n consolidatedOriginalResourceAccess,\n updatedResourceAccessList,\n )\n )\n }, [\n consolidatedOriginalResourceAccess,\n originalIsInherited,\n updatedIsInherited,\n updatedResourceAccessList,\n ])\n\n const canSave =\n hasAclChanged || isLoadingSendMessageToNewACLUsers || isPending\n\n const showInheritedAclUpdateWarning = hasAclChanged && isAfterUpload\n\n useEffect(() => {\n onCanSaveChange(canSave)\n }, [onCanSaveChange, canSave])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n if (canSave) {\n // Check if the inheritance changed; if so, the ACL should be created/deleted\n if (originalIsInherited != updatedIsInherited) {\n if (updatedIsInherited) {\n deleteAcl(entityId)\n } else {\n createAcl({\n id: entityId,\n resourceAccess: updatedResourceAccessList,\n })\n }\n } else {\n // Inheritance did not change; update the ACL\n updateAcl({\n // ensure we get all fields from the original ACL, including the etag\n ...entityBundle.accessControlList!,\n resourceAccess: updatedResourceAccessList,\n })\n }\n } else {\n console.error('EntityAclEditor: save() called but canSave is false')\n }\n },\n }\n },\n [\n canSave,\n createAcl,\n deleteAcl,\n entityBundle,\n entityId,\n originalIsInherited,\n updateAcl,\n updatedIsInherited,\n updatedResourceAccessList,\n ],\n )\n\n return (\n <Stack\n sx={{\n gap: 2,\n }}\n >\n <OpenData\n isOpenData={isOpenData}\n isPublic={isPublic}\n currentUserCanUpdateSharingSettings={canEdit}\n />\n <InheritanceMessage\n isProject={isProject}\n isInherited={updatedIsInherited}\n benefactorId={updatedIsInherited ? parentAcl?.id : entityId}\n isAfterUpload={isAfterUpload}\n />\n {showInheritedAclUpdateWarning && (\n <FullWidthAlert\n isGlobal={false}\n variant={'warning'}\n title={`Edits will affect settings of entire ${entityTypeToFriendlyName(\n entityBundle?.entityType,\n ).toLowerCase()}.`}\n description={\n <>\n <p>\n Editing the settings here will impact the sharing settings for\n all files and folders within this{' '}\n {entityTypeToFriendlyName(\n entityBundle?.entityType,\n ).toLowerCase()}\n , not just the ones you've recently uploaded.\n </p>\n <p>\n View the instructions above for setting your{' '}\n <Link\n href={\n SYNAPSE_DOCS_SHARING_SETTINGS_PERMISSIONS_CONDITIONS_FOR_USE_URL\n }\n target={'_blank'}\n >\n Local Sharing Settings\n </Link>\n .\n </p>\n </>\n }\n />\n )}\n {/* Create / delete local sharing settings button */}\n {!isAfterUpload &&\n !isProject &&\n entityBundle.permissions.canEnableInheritance && (\n <CreateOrDeleteLocalSharingSettingsButton\n isInherited={updatedIsInherited}\n setIsInherited={setUpdatedIsInherited}\n />\n )}\n {error && <Alert severity=\"error\">{error.message}</Alert>}\n <AclEditor\n isInherited={updatedIsInherited}\n canEdit={getCanEditResourceAccess(\n canEdit,\n updatedIsInherited,\n ownProfile,\n publicGroupId,\n )}\n canRemoveEntry={getCanDeleteResourceAccess(\n canEdit,\n updatedIsInherited,\n ownProfile,\n )}\n resourceAccessList={updatedResourceAccessList}\n availablePermissionLevels={availablePermissionLevels}\n emptyText={/* This should never happen */ ''}\n displayedPermissionLevelOverride={getDisplayedPermissionLevelOverride(\n isOpenData,\n publicGroupId,\n )}\n onAddPrincipalToAcl={id => {\n if (publicGroupId !== undefined && String(id) === publicGroupId) {\n addResourceAccessItem(\n id,\n getAccessTypeFromPermissionLevel('CAN_VIEW'),\n )\n } else {\n addResourceAccessItem(\n id,\n getAccessTypeFromPermissionLevel('CAN_DOWNLOAD'),\n )\n }\n }}\n updateResourceAccessItem={updateResourceAccessItem}\n removeResourceAccessItem={removeResourceAccessItem}\n showNotifyCheckbox={true}\n notifyCheckboxValue={notifyNewAdditions}\n onNotifyCheckboxChange={setNotifyNewAdditions}\n showAddRemovePublicButton={true}\n />\n </Stack>\n )\n})\n\nconst EntityAclEditorWithSuspense = forwardRef(\n function EntityAclEditorWithSuspense(\n props: EntityAclEditorProps,\n ref: ForwardedRef<EntityAclEditorHandle>,\n ) {\n return (\n <SynapseErrorBoundary>\n <Suspense fallback={<AclEditorSkeleton />}>\n <EntityAclEditor {...props} ref={ref} />\n </Suspense>\n </SynapseErrorBoundary>\n )\n },\n)\n\nexport default EntityAclEditorWithSuspense\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EntityAclEditor.js","names":[],"sources":["../../../src/components/EntityAclEditor/EntityAclEditor.tsx"],"sourcesContent":["import {\n useCreateEntityACL,\n useDeleteEntityACL,\n useSuspenseGetCurrentUserProfile,\n useSuspenseGetEntityBenefactorACL,\n useSuspenseGetEntityBundle,\n useUpdateEntityACL,\n} from '@/synapse-queries'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { BackendDestinationEnum, getEndpoint } from '@/utils/functions'\nimport {\n consolidateResourceAccessList,\n isEntityPublic,\n resourceAccessListIsEqual,\n} from '@/utils/functions/AccessControlListUtils'\nimport { getPrincipalDisplayName } from '@/utils/functions/getPrincipalDisplayName'\nimport { entityTypeToFriendlyName } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAccessTypeFromPermissionLevel,\n PermissionLevel,\n permissionLevelToLabel,\n} from '@/utils/PermissionLevelToAccessType'\nimport { SYNAPSE_DOCS_SHARING_SETTINGS_PERMISSIONS_CONDITIONS_FOR_USE_URL } from '@/utils/SynapseConstants'\nimport { Alert, Link, Stack } from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n ALL_ENTITY_BUNDLE_FIELDS,\n ResourceAccess,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n Suspense,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { AclEditor, AclEditorProps } from '../AclEditor/AclEditor'\nimport { AclEditorSkeleton } from '../AclEditor/AclEditorSkeleton'\nimport useUpdateAcl from '../AclEditor/useUpdateAcl'\nimport { SynapseErrorBoundary } from '../error'\nimport FullWidthAlert from '../FullWidthAlert'\nimport { CreateOrDeleteLocalSharingSettingsButton } from './CreateOrDeleteLocalSharingSettingsButton'\nimport { InheritanceMessage } from './InheritanceMessage'\nimport OpenData from './OpenData'\nimport useNotifyNewACLUsers from './useNotifyNewACLUsers'\n\nconst availablePermissionLevels: PermissionLevel[] = [\n 'CAN_VIEW',\n 'CAN_DOWNLOAD',\n 'CAN_EDIT',\n 'CAN_EDIT_DELETE',\n 'CAN_ADMINISTER',\n]\n\nexport type EntityAclEditorProps = {\n /** The ID of the entity on which to view/edit the ACL. Note that the ACL may actually belong to an entity ancestor (benefactor). */\n entityId: string\n /** Invoked when the user can/cannot save the pending changes. */\n onCanSaveChange: (canSaveChanges: boolean) => void\n /** Invoked when changes are successfully made. */\n onUpdateSuccess: () => void\n /** Special case to show specific copy and allow changes to an inherited ACL immediately after a file is uploaded.\n * Note that if this is true, the entityId should be the ID of the folder or project that is the benefactor of the newly uploaded file(s)\n * @defaultValue false */\n isAfterUpload?: boolean\n}\n\nexport type EntityAclEditorHandle = {\n save: () => void\n}\n\nfunction getSubject(entityName: string) {\n return `${entityName} (shared on Synapse)`\n}\n\nfunction getBody(profile: UserProfile, entityId: string) {\n return `${getPrincipalDisplayName(\n {\n userName: profile.userName ?? '',\n firstName: profile.firstName,\n lastName: profile.lastName,\n },\n { showFullName: true, showUsername: false },\n )} has shared an item with you on Synapse:\\n${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${entityId}`\n}\n\nfunction getCanEditResourceAccess(\n canEdit: boolean,\n isInherited: boolean,\n ownProfile: UserProfile,\n publicGroupId: string | undefined,\n): AclEditorProps['canEdit'] {\n if (!canEdit || isInherited) {\n return false\n }\n return (resourceAccess: ResourceAccess): boolean => {\n // Users cannot change their own permissions\n const isSelf = ownProfile.ownerId === String(resourceAccess.principalId)\n // Users cannot change permission level for the public group, only add/remove it.\n // To give the public group DOWNLOAD access, ACT must mark it as anonymous access.\n const isPublicGroup =\n publicGroupId !== undefined &&\n String(resourceAccess.principalId) === publicGroupId\n if (isSelf || isPublicGroup) {\n return false\n }\n return true\n }\n}\n\nfunction getCanDeleteResourceAccess(\n canEdit: boolean,\n isInherited: boolean,\n ownProfile: UserProfile,\n): AclEditorProps['canRemoveEntry'] {\n if (!canEdit || isInherited) {\n return false\n }\n return (resourceAccess: ResourceAccess): boolean => {\n // Users cannot delete their own permissions\n const isSelf = ownProfile.ownerId === String(resourceAccess.principalId)\n if (isSelf) {\n return false\n }\n return canEdit\n }\n}\n\nfunction getDisplayedPermissionLevelOverride(\n isOpenData: boolean,\n publicGroupId: string | undefined,\n): AclEditorProps['displayedPermissionLevelOverride'] {\n return (resourceAccess: ResourceAccess) => {\n if (\n publicGroupId !== undefined &&\n String(resourceAccess.principalId) === publicGroupId\n ) {\n return isOpenData\n ? permissionLevelToLabel['CAN_DOWNLOAD']\n : permissionLevelToLabel['CAN_VIEW']\n }\n return undefined\n }\n}\n\nconst EntityAclEditor = forwardRef(function EntityAclEditor(\n props: EntityAclEditorProps,\n ref: ForwardedRef<EntityAclEditorHandle>,\n) {\n const {\n entityId,\n onCanSaveChange,\n onUpdateSuccess,\n isAfterUpload = false,\n } = props\n\n const { data: ownProfile } = useSuspenseGetCurrentUserProfile()\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const { publicGroup: publicGroupId } = realmPrincipals || {}\n const { data: entityBundle } = useSuspenseGetEntityBundle(\n entityId,\n undefined,\n ALL_ENTITY_BUNDLE_FIELDS,\n { staleTime: Infinity },\n )\n const isProject = EntityType.project == entityBundle.entityType\n\n // The parent's benefactor ACL will be shown if the user removes the ACL on the current entity\n const { data: parentAcl } = useSuspenseGetEntityBenefactorACL(\n entityBundle.entity.parentId!,\n {\n staleTime: Infinity,\n },\n )\n\n const consolidatedOriginalResourceAccess = useMemo(\n () =>\n consolidateResourceAccessList(entityBundle.benefactorAcl.resourceAccess),\n [entityBundle.benefactorAcl.resourceAccess],\n )\n\n const parentResourceAccess = useMemo(\n () => parentAcl?.resourceAccess ?? [],\n [parentAcl],\n )\n const canEdit = entityBundle.permissions.canChangePermissions\n const isOpenData = entityBundle.permissions.isEntityOpenData\n const originalIsInherited = !(entityBundle.benefactorAcl.id == entityId)\n const [updatedIsInherited, setUpdatedIsInherited] =\n useState(originalIsInherited)\n const [notifyNewAdditions, setNotifyNewAdditions] = useState(false)\n const [error, setError] = useState<Error>()\n\n const {\n resourceAccessList: updatedResourceAccessList,\n setResourceAccessList,\n addResourceAccessItem,\n updateResourceAccessItem,\n removeResourceAccessItem,\n resetDirtyState,\n } = useUpdateAcl({\n initialResourceAccessList: consolidatedOriginalResourceAccess,\n })\n\n // If `consolidatedOriginalResourceAccess` changes, reset state\n useEffect(() => {\n if (consolidatedOriginalResourceAccess) {\n resetDirtyState()\n setResourceAccessList([...consolidatedOriginalResourceAccess])\n }\n }, [\n consolidatedOriginalResourceAccess,\n resetDirtyState,\n setResourceAccessList,\n ])\n\n // If `originalIsInherited` changes, reset state\n useEffect(() => {\n resetDirtyState()\n setUpdatedIsInherited(originalIsInherited)\n }, [originalIsInherited, resetDirtyState])\n\n // If the editor toggles the inherited state, reset the resource access list\n useEffect(() => {\n if (originalIsInherited == updatedIsInherited) {\n // The user reverted to the original state (regardless of inherited or not)\n setResourceAccessList(consolidatedOriginalResourceAccess)\n } else if (updatedIsInherited) {\n // The user toggled to inherited, update the resource access list to match the parent\n setResourceAccessList(parentResourceAccess)\n } else {\n // The user toggled to local, no need to update the list (the parent's list is already in the editor)\n }\n resetDirtyState()\n }, [\n originalIsInherited,\n consolidatedOriginalResourceAccess,\n parentResourceAccess,\n resetDirtyState,\n setResourceAccessList,\n updatedIsInherited,\n ])\n\n const isPublic = isEntityPublic(\n updatedResourceAccessList,\n realmPrincipals ?? {},\n )\n\n const {\n sendNotification,\n isLoading: isLoadingSendMessageToNewACLUsers,\n isPending: isPendingSendMessageToNewACLUsers,\n } = useNotifyNewACLUsers({\n subject: getSubject(entityBundle.entity.name || ''),\n body: getBody(ownProfile, entityId),\n initialResourceAccessList: consolidatedOriginalResourceAccess,\n newResourceAccessList: updatedResourceAccessList,\n })\n\n const mutationOptions = {\n onSuccess: () => {\n if (notifyNewAdditions) {\n sendNotification()\n }\n onUpdateSuccess()\n },\n onError: (e: Error) => {\n setError(e)\n },\n }\n\n const { mutate: createAcl, isPending: isPendingCreateAcl } =\n useCreateEntityACL(mutationOptions)\n const { mutate: updateAcl, isPending: isPendingUpdateAcl } =\n useUpdateEntityACL(mutationOptions)\n const { mutate: deleteAcl, isPending: isPendingDeleteAcl } =\n useDeleteEntityACL(mutationOptions)\n\n const isPending =\n isPendingCreateAcl ||\n isPendingUpdateAcl ||\n isPendingDeleteAcl ||\n isPendingSendMessageToNewACLUsers\n\n const hasAclChanged = useMemo(() => {\n return (\n originalIsInherited != updatedIsInherited ||\n !resourceAccessListIsEqual(\n consolidatedOriginalResourceAccess,\n updatedResourceAccessList,\n )\n )\n }, [\n consolidatedOriginalResourceAccess,\n originalIsInherited,\n updatedIsInherited,\n updatedResourceAccessList,\n ])\n\n const canSave =\n hasAclChanged || isLoadingSendMessageToNewACLUsers || isPending\n\n const showInheritedAclUpdateWarning = hasAclChanged && isAfterUpload\n\n useEffect(() => {\n onCanSaveChange(canSave)\n }, [onCanSaveChange, canSave])\n\n useImperativeHandle(ref, () => {\n return {\n save() {\n if (canSave) {\n // Check if the inheritance changed; if so, the ACL should be created/deleted\n if (originalIsInherited != updatedIsInherited) {\n if (updatedIsInherited) {\n deleteAcl(entityId)\n } else {\n createAcl({\n id: entityId,\n resourceAccess: updatedResourceAccessList,\n })\n }\n } else {\n // Inheritance did not change; update the ACL\n updateAcl({\n // ensure we get all fields from the original ACL, including the etag\n ...entityBundle.accessControlList!,\n resourceAccess: updatedResourceAccessList,\n })\n }\n } else {\n console.error('EntityAclEditor: save() called but canSave is false')\n }\n },\n }\n }, [\n canSave,\n createAcl,\n deleteAcl,\n entityBundle,\n entityId,\n originalIsInherited,\n updateAcl,\n updatedIsInherited,\n updatedResourceAccessList,\n ])\n\n return (\n <Stack\n sx={{\n gap: 2,\n }}\n >\n <OpenData\n isOpenData={isOpenData}\n isPublic={isPublic}\n currentUserCanUpdateSharingSettings={canEdit}\n />\n <InheritanceMessage\n isProject={isProject}\n isInherited={updatedIsInherited}\n benefactorId={updatedIsInherited ? parentAcl?.id : entityId}\n isAfterUpload={isAfterUpload}\n />\n {showInheritedAclUpdateWarning && (\n <FullWidthAlert\n isGlobal={false}\n variant={'warning'}\n title={`Edits will affect settings of entire ${entityTypeToFriendlyName(\n entityBundle?.entityType,\n ).toLowerCase()}.`}\n description={\n <>\n <p>\n Editing the settings here will impact the sharing settings for\n all files and folders within this{' '}\n {entityTypeToFriendlyName(\n entityBundle?.entityType,\n ).toLowerCase()}\n , not just the ones you've recently uploaded.\n </p>\n <p>\n View the instructions above for setting your{' '}\n <Link\n href={\n SYNAPSE_DOCS_SHARING_SETTINGS_PERMISSIONS_CONDITIONS_FOR_USE_URL\n }\n target={'_blank'}\n >\n Local Sharing Settings\n </Link>\n .\n </p>\n </>\n }\n />\n )}\n {/* Create / delete local sharing settings button */}\n {!isAfterUpload &&\n !isProject &&\n entityBundle.permissions.canEnableInheritance && (\n <CreateOrDeleteLocalSharingSettingsButton\n isInherited={updatedIsInherited}\n setIsInherited={setUpdatedIsInherited}\n />\n )}\n {error && <Alert severity=\"error\">{error.message}</Alert>}\n <AclEditor\n isInherited={updatedIsInherited}\n canEdit={getCanEditResourceAccess(\n canEdit,\n updatedIsInherited,\n ownProfile,\n publicGroupId,\n )}\n canRemoveEntry={getCanDeleteResourceAccess(\n canEdit,\n updatedIsInherited,\n ownProfile,\n )}\n resourceAccessList={updatedResourceAccessList}\n availablePermissionLevels={availablePermissionLevels}\n emptyText={/* This should never happen */ ''}\n displayedPermissionLevelOverride={getDisplayedPermissionLevelOverride(\n isOpenData,\n publicGroupId,\n )}\n onAddPrincipalToAcl={id => {\n if (publicGroupId !== undefined && String(id) === publicGroupId) {\n addResourceAccessItem(\n id,\n getAccessTypeFromPermissionLevel('CAN_VIEW'),\n )\n } else {\n addResourceAccessItem(\n id,\n getAccessTypeFromPermissionLevel('CAN_DOWNLOAD'),\n )\n }\n }}\n updateResourceAccessItem={updateResourceAccessItem}\n removeResourceAccessItem={removeResourceAccessItem}\n showNotifyCheckbox={true}\n notifyCheckboxValue={notifyNewAdditions}\n onNotifyCheckboxChange={setNotifyNewAdditions}\n showAddRemovePublicButton={true}\n />\n </Stack>\n )\n})\n\nconst EntityAclEditorWithSuspense = forwardRef(\n function EntityAclEditorWithSuspense(\n props: EntityAclEditorProps,\n ref: ForwardedRef<EntityAclEditorHandle>,\n ) {\n return (\n <SynapseErrorBoundary>\n <Suspense fallback={<AclEditorSkeleton />}>\n <EntityAclEditor {...props} ref={ref} />\n </Suspense>\n </SynapseErrorBoundary>\n )\n },\n)\n\nexport default EntityAclEditorWithSuspense\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityBadgeIcons.d.ts","sourceRoot":"","sources":["../../../src/components/EntityBadgeIcons/EntityBadgeIcons.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAOlD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"EntityBadgeIcons.d.ts","sourceRoot":"","sources":["../../../src/components/EntityBadgeIcons/EntityBadgeIcons.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAOlD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EACL,MAAM,GACN,QAAQ,GACR,cAAc,GACd,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,cAAc,CAAA;IAClB,cAAc,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAA;IACnD,qFAAqF;IACrF,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,oFAAoF;IACpF,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,+HAA+H;IAC/H,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0FAA0F;IAC1F,uBAAuB,CAAC,EAAE,OAAO,CAAA;IAEjC,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC,wFAAwF;IACxF,YAAY,EAAE,OAAO,CAAA;CACtB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,qBAAqB,KAC3B,KAAK,CAAC,SAqSR,CAAA;AAED,eAAe,gBAAgB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityBadgeIcons.js","names":[],"sources":["../../../src/components/EntityBadgeIcons/EntityBadgeIcons.tsx"],"sourcesContent":["import {\n useDeleteEntity,\n useGetEntityBundle,\n useGetJson,\n useGetSchemaBinding,\n useGetValidationResults,\n} from '@/synapse-queries'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n ChatBubbleTwoTone,\n CheckTwoTone,\n DescriptionTwoTone,\n LinkOffTwoTone,\n LocalOfferTwoTone,\n LockTwoTone,\n PublicTwoTone,\n} from '@mui/icons-material'\nimport { Tooltip } from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { ALL_ENTITY_BUNDLE_FIELDS } from '@sage-bionetworks/synapse-types'\nimport { isEmpty } from 'lodash-es'\nimport React, { useEffect, useState } from 'react'\nimport { useInView } from 'react-intersection-observer'\nimport { getDisplayedAnnotation } from '../entity/metadata/AnnotationsTable'\nimport { EntityModal } from '../entity/metadata/EntityModal'\nimport { HoverPopover } from '../styled/HoverPopover'\nimport WarningDialog from '../SynapseForm/WarningDialog'\n\nexport type EntityBadgeIconsProps = {\n entityId: string\n versionNumber?: number\n flexWrap?: // possible settings for flex-wrap\n | 'wrap'\n | 'nowrap'\n | '-moz-initial'\n | 'inherit'\n | 'initial'\n | 'revert'\n | 'unset'\n | 'wrap-reverse'\n justifyContent?: 'flex-start' | 'flex-end' | string\n /** Shows an icon indicating if the entity is 'public' or 'private'. Default true */\n showIsPublicPrivate?: boolean\n /** Shows an icon if the entity has sharing settings set on itself. Default true */\n showHasLocalSharingSettings?: boolean\n /** Shows an icon if the entity has annotations, or if it has a validation schema (in experimental mode only). Default true */\n showHasAnnotations?: boolean\n /** Shows an icon if the entity a wiki. Default true */\n showHasWiki?: boolean\n /** Shows an icon if the entity has been mentioned in discussion threads. Default true */\n showHasDiscussionThread?: boolean\n /* Shows an 'unlink' button if the entity is a link and the user has permission to delete it. Default true */\n showUnlink?: boolean\n /* Invoked after the entity is unlinked/deleted in case there is cleanup to do. Returns the entityId */\n onUnlink?: (entityId: string) => void\n onUnlinkError?: (error: unknown) => void\n /** Whether or not the badges (e.g. Annotations) can trigger opening a modal on click */\n canOpenModal: boolean\n}\n\n/**\n * Stateless component used to show icons that show an entity's status.\n * Adapted from https://github.com/Sage-Bionetworks/SynapseWebClient/blob/46b9b717636cda2421926d96365244bbb72a05b6/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityBadge.java\n */\nexport const EntityBadgeIcons = (\n props: EntityBadgeIconsProps,\n): React.ReactNode => {\n const {\n entityId,\n versionNumber,\n flexWrap = 'nowrap',\n justifyContent = 'flex-start',\n showIsPublicPrivate = true,\n showHasLocalSharingSettings = true,\n showHasAnnotations = true,\n showHasWiki = true,\n showHasDiscussionThread = true,\n showUnlink = true,\n onUnlink = () => {\n /* noop */\n },\n onUnlinkError = () => {\n /* noop */\n },\n canOpenModal,\n } = props\n\n const { data } = useGetRealmPrincipals()\n const realmPrincipals = data || {}\n\n enum SchemaConformanceState {\n NO_SCHEMA = '', // or not in experimental mode\n VALID = 'Valid',\n INVALID = 'Invalid',\n ANNOTATIONS_MISSING = 'Missing',\n }\n\n const { ref, inView } = useInView()\n\n const { data: entityData } = useGetJson(entityId, versionNumber, true, {\n enabled: inView,\n })\n const annotations = entityData?.annotations\n const { data: bundle } = useGetEntityBundle(\n entityId,\n versionNumber,\n ALL_ENTITY_BUNDLE_FIELDS,\n {\n enabled: inView,\n },\n )\n const [showModal, setShowModal] = useState(false)\n const [showUnlinkConfirmModal, setShowUnlinkConfirmModal] = useState(false)\n const [schemaConformance, setSchemaConformance] = useState(\n SchemaConformanceState.NO_SCHEMA,\n )\n\n const { data: boundSchema } = useGetSchemaBinding(entityId, {\n enabled: inView,\n staleTime: 60 * 1000, // 60 seconds\n })\n\n const { data: schemaValidationResults } = useGetValidationResults(entityId, {\n enabled: inView && !!boundSchema,\n staleTime: 60 * 1000, // 60 seconds\n })\n\n const annotationsCount =\n annotations && !isEmpty(annotations) ? Object.keys(annotations).length : 0\n useEffect(() => {\n if (schemaValidationResults) {\n if (schemaValidationResults.isValid) {\n setSchemaConformance(SchemaConformanceState.VALID)\n } else if (annotationsCount) {\n // If annotations exist, then indicate that they are invalid\n setSchemaConformance(SchemaConformanceState.INVALID)\n } else {\n // If annotations are missing, it's still invalid, but should appear differently\n setSchemaConformance(SchemaConformanceState.ANNOTATIONS_MISSING)\n }\n }\n }, [\n schemaValidationResults,\n annotationsCount,\n annotations,\n SchemaConformanceState.VALID,\n SchemaConformanceState.INVALID,\n SchemaConformanceState.ANNOTATIONS_MISSING,\n ])\n\n const { mutate: unlinkEntity } = useDeleteEntity({\n onSuccess: (_, entityId) => {\n onUnlink(entityId)\n },\n onError: onUnlinkError,\n })\n\n /**\n * Convert the list of annotations to a string of <tr>...anno1</tr><tr>...anno2</tr>...\n * If there are no annotations, this is the empty string ('')\n */\n const annotationsTableRows = (\n <>\n {annotations\n ? Object.entries(annotations ?? []).map(([key, value]) => (\n <tr key={key}>\n <td>\n <b>{key}</b>\n </td>\n <td>\n {Array.isArray(value)\n ? value.map(getDisplayedAnnotation).join(', ')\n : getDisplayedAnnotation(value as string | number | boolean)}\n </td>\n </tr>\n ))\n : ''}\n </>\n )\n // We also show the schema name if there is one (and we're in experimental mode)\n const valiationSchemaTableRow = (\n <>\n {boundSchema ? (\n <tr>\n <td>\n <b>Validation Schema</b>\n </td>\n <td>{boundSchema.jsonSchemaVersionInfo.schemaName}</td>\n </tr>\n ) : (\n ''\n )}\n </>\n )\n const annotationsTitle = schemaValidationResults\n ? `${schemaConformance} Annotations`\n : ''\n const annotationsHtml = (\n <div className=\"EntityBadgeTooltip\">\n <table>\n <tbody>\n {annotationsTableRows ? annotationsTableRows : ''}\n {valiationSchemaTableRow}\n </tbody>\n </table>\n </div>\n )\n\n return (\n <div className=\"EntityBadge\" ref={ref} style={{ flexWrap, justifyContent }}>\n {bundle && (\n <>\n <div onClick={e => e.stopPropagation()}>\n <EntityModal\n entityId={entityId}\n show={showModal}\n showTabs={false}\n onClose={() => setShowModal(false)}\n initialTab={'ANNOTATIONS'}\n />\n </div>\n {showIsPublicPrivate &&\n bundle.benefactorAcl &&\n isEntityPublic(\n bundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n ) ? (\n <Tooltip title=\"Public\" enterNextDelay={100} placement=\"right\">\n <PublicTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'is-public-icon'}\n />\n </Tooltip>\n ) : null}\n {showIsPublicPrivate &&\n bundle.benefactorAcl &&\n !isEntityPublic(\n bundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n ) ? (\n <Tooltip title=\"Private\" enterNextDelay={100} placement=\"right\">\n <LockTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'is-private-icon'}\n />\n </Tooltip>\n ) : null}\n {showHasLocalSharingSettings &&\n bundle.benefactorAcl &&\n entityId === bundle.benefactorAcl.id ? (\n <Tooltip\n title=\"Sharing Settings have been set\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <CheckTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'sharing-settings-icon'}\n />\n </Tooltip>\n ) : null}\n\n {showHasAnnotations &&\n !!(annotationsCount || schemaValidationResults) && (\n <HoverPopover\n title={annotationsTitle}\n popoverContent={annotationsHtml}\n placement=\"right\"\n maxWidth={500}\n actionButton={\n canOpenModal\n ? {\n content: 'Edit Annotations',\n onClick: () => setShowModal(true),\n closeOnClick: true,\n }\n : undefined\n }\n >\n <LocalOfferTwoTone\n aria-hidden={false}\n role={canOpenModal ? 'button' : 'img'}\n className={`EntityBadge__Badge ${schemaConformance}`}\n data-html={true}\n data-testid={'annotations-icon'}\n />\n </HoverPopover>\n )}\n {showHasWiki && bundle.rootWikiId && (\n <Tooltip title=\"Has a wiki\" enterNextDelay={100} placement=\"right\">\n <DescriptionTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'wiki-icon'}\n />\n </Tooltip>\n )}\n {showHasDiscussionThread &&\n !!bundle.threadCount &&\n !!(bundle.threadCount > 0) && (\n <Tooltip\n title=\"Has been mentioned in discussion\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <ChatBubbleTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'discussion-icon'}\n />\n </Tooltip>\n )}\n {showUnlink &&\n bundle.entityType === EntityType.link &&\n bundle.permissions?.canDelete && (\n <>\n <WarningDialog\n open={showUnlinkConfirmModal}\n title=\"Confirm Unlink\"\n content={\n 'Are you sure you want to remove this link? The original object will not be changed.'\n }\n confirmButtonText=\"Unlink\"\n confirmButtonColor=\"error\"\n onConfirm={() => {\n unlinkEntity(entityId)\n setShowUnlinkConfirmModal(false)\n }}\n onCancel={() => {\n setShowUnlinkConfirmModal(false)\n }}\n />\n <Tooltip\n title=\"Remove this link\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <LinkOffTwoTone\n aria-hidden={false}\n role=\"button\"\n onClick={() => setShowUnlinkConfirmModal(true)}\n className=\"EntityBadge__Badge Unlink\"\n data-testid={'unlink-icon'}\n />\n </Tooltip>\n </>\n )}\n </>\n )}\n </div>\n )\n}\n\nexport default EntityBadgeIcons\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EntityBadgeIcons.js","names":[],"sources":["../../../src/components/EntityBadgeIcons/EntityBadgeIcons.tsx"],"sourcesContent":["import {\n useDeleteEntity,\n useGetEntityBundle,\n useGetJson,\n useGetSchemaBinding,\n useGetValidationResults,\n} from '@/synapse-queries'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n ChatBubbleTwoTone,\n CheckTwoTone,\n DescriptionTwoTone,\n LinkOffTwoTone,\n LocalOfferTwoTone,\n LockTwoTone,\n PublicTwoTone,\n} from '@mui/icons-material'\nimport { Tooltip } from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { ALL_ENTITY_BUNDLE_FIELDS } from '@sage-bionetworks/synapse-types'\nimport { isEmpty } from 'lodash-es'\nimport React, { useEffect, useState } from 'react'\nimport { useInView } from 'react-intersection-observer'\nimport { getDisplayedAnnotation } from '../entity/metadata/AnnotationsTable'\nimport { EntityModal } from '../entity/metadata/EntityModal'\nimport { HoverPopover } from '../styled/HoverPopover'\nimport WarningDialog from '../SynapseForm/WarningDialog'\n\nexport type EntityBadgeIconsProps = {\n entityId: string\n versionNumber?: number\n flexWrap?: // possible settings for flex-wrap\n | 'wrap'\n | 'nowrap'\n | '-moz-initial'\n | 'inherit'\n | 'initial'\n | 'revert'\n | 'unset'\n | 'wrap-reverse'\n justifyContent?: 'flex-start' | 'flex-end' | string\n /** Shows an icon indicating if the entity is 'public' or 'private'. Default true */\n showIsPublicPrivate?: boolean\n /** Shows an icon if the entity has sharing settings set on itself. Default true */\n showHasLocalSharingSettings?: boolean\n /** Shows an icon if the entity has annotations, or if it has a validation schema (in experimental mode only). Default true */\n showHasAnnotations?: boolean\n /** Shows an icon if the entity a wiki. Default true */\n showHasWiki?: boolean\n /** Shows an icon if the entity has been mentioned in discussion threads. Default true */\n showHasDiscussionThread?: boolean\n /* Shows an 'unlink' button if the entity is a link and the user has permission to delete it. Default true */\n showUnlink?: boolean\n /* Invoked after the entity is unlinked/deleted in case there is cleanup to do. Returns the entityId */\n onUnlink?: (entityId: string) => void\n onUnlinkError?: (error: unknown) => void\n /** Whether or not the badges (e.g. Annotations) can trigger opening a modal on click */\n canOpenModal: boolean\n}\n\n/**\n * Stateless component used to show icons that show an entity's status.\n * Adapted from https://github.com/Sage-Bionetworks/SynapseWebClient/blob/46b9b717636cda2421926d96365244bbb72a05b6/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityBadge.java\n */\nexport const EntityBadgeIcons = (\n props: EntityBadgeIconsProps,\n): React.ReactNode => {\n const {\n entityId,\n versionNumber,\n flexWrap = 'nowrap',\n justifyContent = 'flex-start',\n showIsPublicPrivate = true,\n showHasLocalSharingSettings = true,\n showHasAnnotations = true,\n showHasWiki = true,\n showHasDiscussionThread = true,\n showUnlink = true,\n onUnlink = () => {\n /* noop */\n },\n onUnlinkError = () => {\n /* noop */\n },\n canOpenModal,\n } = props\n\n const { data } = useGetRealmPrincipals()\n const realmPrincipals = data || {}\n\n enum SchemaConformanceState {\n NO_SCHEMA = '', // or not in experimental mode\n VALID = 'Valid',\n INVALID = 'Invalid',\n ANNOTATIONS_MISSING = 'Missing',\n }\n\n const { ref, inView } = useInView()\n\n const { data: entityData } = useGetJson(entityId, versionNumber, true, {\n enabled: inView,\n })\n const annotations = entityData?.annotations\n const { data: bundle } = useGetEntityBundle(\n entityId,\n versionNumber,\n ALL_ENTITY_BUNDLE_FIELDS,\n {\n enabled: inView,\n },\n )\n const [showModal, setShowModal] = useState(false)\n const [showUnlinkConfirmModal, setShowUnlinkConfirmModal] = useState(false)\n const [schemaConformance, setSchemaConformance] = useState(\n SchemaConformanceState.NO_SCHEMA,\n )\n\n const { data: boundSchema } = useGetSchemaBinding(entityId, {\n enabled: inView,\n staleTime: 60 * 1000, // 60 seconds\n })\n\n const { data: schemaValidationResults } = useGetValidationResults(entityId, {\n enabled: inView && !!boundSchema,\n staleTime: 60 * 1000, // 60 seconds\n })\n\n const annotationsCount =\n annotations && !isEmpty(annotations) ? Object.keys(annotations).length : 0\n useEffect(() => {\n if (schemaValidationResults) {\n if (schemaValidationResults.isValid) {\n setSchemaConformance(SchemaConformanceState.VALID)\n } else if (annotationsCount) {\n // If annotations exist, then indicate that they are invalid\n setSchemaConformance(SchemaConformanceState.INVALID)\n } else {\n // If annotations are missing, it's still invalid, but should appear differently\n setSchemaConformance(SchemaConformanceState.ANNOTATIONS_MISSING)\n }\n }\n }, [\n schemaValidationResults,\n annotationsCount,\n annotations,\n SchemaConformanceState.VALID,\n SchemaConformanceState.INVALID,\n SchemaConformanceState.ANNOTATIONS_MISSING,\n ])\n\n const { mutate: unlinkEntity } = useDeleteEntity({\n onSuccess: (_, entityId) => {\n onUnlink(entityId)\n },\n onError: onUnlinkError,\n })\n\n /**\n * Convert the list of annotations to a string of <tr>...anno1</tr><tr>...anno2</tr>...\n * If there are no annotations, this is the empty string ('')\n */\n const annotationsTableRows = (\n <>\n {annotations\n ? Object.entries(annotations ?? []).map(([key, value]) => (\n <tr key={key}>\n <td>\n <b>{key}</b>\n </td>\n <td>\n {Array.isArray(value)\n ? value.map(getDisplayedAnnotation).join(', ')\n : getDisplayedAnnotation(value as string | number | boolean)}\n </td>\n </tr>\n ))\n : ''}\n </>\n )\n // We also show the schema name if there is one (and we're in experimental mode)\n const valiationSchemaTableRow = (\n <>\n {boundSchema ? (\n <tr>\n <td>\n <b>Validation Schema</b>\n </td>\n <td>{boundSchema.jsonSchemaVersionInfo.schemaName}</td>\n </tr>\n ) : (\n ''\n )}\n </>\n )\n const annotationsTitle = schemaValidationResults\n ? `${schemaConformance} Annotations`\n : ''\n const annotationsHtml = (\n <div className=\"EntityBadgeTooltip\">\n <table>\n <tbody>\n {annotationsTableRows ? annotationsTableRows : ''}\n {valiationSchemaTableRow}\n </tbody>\n </table>\n </div>\n )\n\n return (\n <div className=\"EntityBadge\" ref={ref} style={{ flexWrap, justifyContent }}>\n {bundle && (\n <>\n <div onClick={e => e.stopPropagation()}>\n <EntityModal\n entityId={entityId}\n show={showModal}\n showTabs={false}\n onClose={() => setShowModal(false)}\n initialTab={'ANNOTATIONS'}\n />\n </div>\n {showIsPublicPrivate &&\n bundle.benefactorAcl &&\n isEntityPublic(\n bundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n ) ? (\n <Tooltip title=\"Public\" enterNextDelay={100} placement=\"right\">\n <PublicTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'is-public-icon'}\n />\n </Tooltip>\n ) : null}\n {showIsPublicPrivate &&\n bundle.benefactorAcl &&\n !isEntityPublic(\n bundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n ) ? (\n <Tooltip title=\"Private\" enterNextDelay={100} placement=\"right\">\n <LockTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'is-private-icon'}\n />\n </Tooltip>\n ) : null}\n {showHasLocalSharingSettings &&\n bundle.benefactorAcl &&\n entityId === bundle.benefactorAcl.id ? (\n <Tooltip\n title=\"Sharing Settings have been set\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <CheckTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'sharing-settings-icon'}\n />\n </Tooltip>\n ) : null}\n\n {showHasAnnotations &&\n !!(annotationsCount || schemaValidationResults) && (\n <HoverPopover\n title={annotationsTitle}\n popoverContent={annotationsHtml}\n placement=\"right\"\n maxWidth={500}\n actionButton={\n canOpenModal\n ? {\n content: 'Edit Annotations',\n onClick: () => setShowModal(true),\n closeOnClick: true,\n }\n : undefined\n }\n >\n <LocalOfferTwoTone\n aria-hidden={false}\n role={canOpenModal ? 'button' : 'img'}\n className={`EntityBadge__Badge ${schemaConformance}`}\n data-html={true}\n data-testid={'annotations-icon'}\n />\n </HoverPopover>\n )}\n {showHasWiki && bundle.rootWikiId && (\n <Tooltip title=\"Has a wiki\" enterNextDelay={100} placement=\"right\">\n <DescriptionTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'wiki-icon'}\n />\n </Tooltip>\n )}\n {showHasDiscussionThread &&\n !!bundle.threadCount &&\n !!(bundle.threadCount > 0) && (\n <Tooltip\n title=\"Has been mentioned in discussion\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <ChatBubbleTwoTone\n aria-hidden={false}\n role=\"img\"\n className=\"EntityBadge__Badge\"\n data-testid={'discussion-icon'}\n />\n </Tooltip>\n )}\n {showUnlink &&\n bundle.entityType === EntityType.link &&\n bundle.permissions?.canDelete && (\n <>\n <WarningDialog\n open={showUnlinkConfirmModal}\n title=\"Confirm Unlink\"\n content={\n 'Are you sure you want to remove this link? The original object will not be changed.'\n }\n confirmButtonText=\"Unlink\"\n confirmButtonColor=\"error\"\n onConfirm={() => {\n unlinkEntity(entityId)\n setShowUnlinkConfirmModal(false)\n }}\n onCancel={() => {\n setShowUnlinkConfirmModal(false)\n }}\n />\n <Tooltip\n title=\"Remove this link\"\n enterNextDelay={100}\n placement=\"right\"\n >\n <LinkOffTwoTone\n aria-hidden={false}\n role=\"button\"\n onClick={() => setShowUnlinkConfirmModal(true)}\n className=\"EntityBadge__Badge Unlink\"\n data-testid={'unlink-icon'}\n />\n </Tooltip>\n </>\n )}\n </>\n )}\n </div>\n )\n}\n\nexport default EntityBadgeIcons\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityCitationUtils.js","names":[],"sources":["../../../src/components/EntityCitation/EntityCitationUtils.ts"],"sourcesContent":["import { useGetDOIAssociation } from '@/synapse-queries/doi/useDOI'\nimport { isVersionableEntity } from '@/utils/functions/EntityTypeUtils'\nimport { DoiObjectType } from '@sage-bionetworks/synapse-client'\nimport { EntityBundle } from '@sage-bionetworks/synapse-types'\n\nexport function useGetEntityDoiAssociation(\n entityId?: string,\n versionNumber?: number,\n projectId?: string,\n bundle?: EntityBundle,\n) {\n const useFallbackVersionlessDOI =\n bundle &&\n !bundle.doiAssociation &&\n isVersionableEntity(bundle.entity) &&\n bundle.entity.isLatestVersion\n\n // Try fetching the versioned DOI first\n const { data: versionedDoiAssociation } = useGetDOIAssociation(\n {\n id: entityId!,\n version: versionNumber,\n type: DoiObjectType.ENTITY,\n },\n {\n enabled: !!entityId && !!versionNumber,\n },\n )\n\n // If the versioned DOI is not found, fallback to the versionless DOI so we can still show a DOI if it exists.\n // We do not want to show the versionless DOI if the entity is not the latest version as it would be misleading.\n const { data: versionlessDoiAssociation } = useGetDOIAssociation(\n {\n id: entityId!,\n version: undefined,\n type: DoiObjectType.ENTITY,\n },\n {\n enabled: useFallbackVersionlessDOI,\n },\n )\n\n const doiAssociation =\n projectId === entityId\n ? undefined\n : versionedDoiAssociation ?? versionlessDoiAssociation\n\n return doiAssociation\n}\n"],"mappings":";;;;AAKA,SAAgB,EACd,GACA,GACA,GACA,GACA;CACA,IAAM,IACJ,KACA,CAAC,EAAO,kBACR,EAAoB,EAAO,OAAO,IAClC,EAAO,OAAO,iBAGV,EAAE,MAAM,MAA4B,EACxC;EACE,IAAI;EACJ,SAAS;EACT,MAAM,EAAc;EACrB,EACD,EACE,SAAS,CAAC,CAAC,KAAY,CAAC,CAAC,GAC1B,CACF,EAIK,EAAE,MAAM,MAA8B,EAC1C;EACE,IAAI;EACJ,SAAS,KAAA;EACT,MAAM,EAAc;EACrB,EACD,EACE,SAAS,GACV,CACF;AAOD,QAJE,MAAc,IACV,KAAA,
|
|
1
|
+
{"version":3,"file":"EntityCitationUtils.js","names":[],"sources":["../../../src/components/EntityCitation/EntityCitationUtils.ts"],"sourcesContent":["import { useGetDOIAssociation } from '@/synapse-queries/doi/useDOI'\nimport { isVersionableEntity } from '@/utils/functions/EntityTypeUtils'\nimport { DoiObjectType } from '@sage-bionetworks/synapse-client'\nimport { EntityBundle } from '@sage-bionetworks/synapse-types'\n\nexport function useGetEntityDoiAssociation(\n entityId?: string,\n versionNumber?: number,\n projectId?: string,\n bundle?: EntityBundle,\n) {\n const useFallbackVersionlessDOI =\n bundle &&\n !bundle.doiAssociation &&\n isVersionableEntity(bundle.entity) &&\n bundle.entity.isLatestVersion\n\n // Try fetching the versioned DOI first\n const { data: versionedDoiAssociation } = useGetDOIAssociation(\n {\n id: entityId!,\n version: versionNumber,\n type: DoiObjectType.ENTITY,\n },\n {\n enabled: !!entityId && !!versionNumber,\n },\n )\n\n // If the versioned DOI is not found, fallback to the versionless DOI so we can still show a DOI if it exists.\n // We do not want to show the versionless DOI if the entity is not the latest version as it would be misleading.\n const { data: versionlessDoiAssociation } = useGetDOIAssociation(\n {\n id: entityId!,\n version: undefined,\n type: DoiObjectType.ENTITY,\n },\n {\n enabled: useFallbackVersionlessDOI,\n },\n )\n\n const doiAssociation =\n projectId === entityId\n ? undefined\n : (versionedDoiAssociation ?? versionlessDoiAssociation)\n\n return doiAssociation\n}\n"],"mappings":";;;;AAKA,SAAgB,EACd,GACA,GACA,GACA,GACA;CACA,IAAM,IACJ,KACA,CAAC,EAAO,kBACR,EAAoB,EAAO,OAAO,IAClC,EAAO,OAAO,iBAGV,EAAE,MAAM,MAA4B,EACxC;EACE,IAAI;EACJ,SAAS;EACT,MAAM,EAAc;EACrB,EACD,EACE,SAAS,CAAC,CAAC,KAAY,CAAC,CAAC,GAC1B,CACF,EAIK,EAAE,MAAM,MAA8B,EAC1C;EACE,IAAI;EACJ,SAAS,KAAA;EACT,MAAM,EAAc;EACrB,EACD,EACE,SAAS,GACV,CACF;AAOD,QAJE,MAAc,IACV,KAAA,IACC,KAA2B"}
|