mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #33166 from overleaf/ii-share-modal-copy-link
[web] Share modal copy sharing link button GitOrigin-RevId: a95f879196528ec3bc998558a6838c52aac33069
This commit is contained in:
@@ -387,6 +387,7 @@
|
||||
"copy": "",
|
||||
"copy_project": "",
|
||||
"copy_response": "",
|
||||
"copy_sharing_link": "",
|
||||
"copying": "",
|
||||
"cost_summary": "",
|
||||
"could_not_save_reference_to_bib_file": "",
|
||||
@@ -1126,6 +1127,7 @@
|
||||
"link_account": "",
|
||||
"link_accounts": "",
|
||||
"link_accounts_and_add_email": "",
|
||||
"link_copied": "",
|
||||
"link_institutional_email_get_started": "",
|
||||
"link_sharing": "",
|
||||
"link_sharing_is_off_short": "",
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import { useShareProjectContext } from '@/features/share-project-modal/components/share-project-modal'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import { useUserContext } from '@/shared/context/user-context'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
export default function CopySharingLinkButton() {
|
||||
const { t } = useTranslation()
|
||||
const { sharingLinkData, projectAccess, setSuccessActionMessage } =
|
||||
useShareProjectContext()
|
||||
const { projectId } = useProjectContext()
|
||||
const { isAdmin } = useUserContext()
|
||||
|
||||
const isCopyBtnEnabled =
|
||||
Boolean(navigator.clipboard?.writeText) &&
|
||||
Boolean(sharingLinkData?.token) &&
|
||||
(projectAccess === 'anyoneInXyzWithTheLink' ||
|
||||
projectAccess === 'anyoneWithTheLink')
|
||||
|
||||
const handleCopyClick = () => {
|
||||
if (!sharingLinkData?.token) {
|
||||
return
|
||||
}
|
||||
|
||||
const origin = isAdmin
|
||||
? getMeta('ol-ExposedSettings').siteUrl
|
||||
: window.location.origin
|
||||
const link = `${origin}/project/${projectId}/share#${sharingLinkData.token}`
|
||||
|
||||
navigator.clipboard
|
||||
.writeText(link)
|
||||
.then(() => setSuccessActionMessage(t('link_copied')))
|
||||
.catch(debugConsole.error)
|
||||
}
|
||||
|
||||
return (
|
||||
<OLButton
|
||||
variant="secondary"
|
||||
leadingIcon={isCopyBtnEnabled ? 'link' : 'link_off'}
|
||||
disabled={!isCopyBtnEnabled}
|
||||
onClick={handleCopyClick}
|
||||
>
|
||||
{t('copy_sharing_link')}
|
||||
</OLButton>
|
||||
)
|
||||
}
|
||||
@@ -92,7 +92,7 @@ function ProjectAccess({
|
||||
|
||||
return data
|
||||
}).then(data => {
|
||||
setSharingLinkData(newAccess === 'onlyInvitedPeople' ? null : data)
|
||||
setSharingLinkData(data)
|
||||
setProjectAccess(newAccess)
|
||||
setSuccessActionMessage(t('access_updated'))
|
||||
})
|
||||
|
||||
+8
-1
@@ -14,6 +14,7 @@ import OLNotification from '@/shared/components/ol/ol-notification'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import OLSpinner from '@/shared/components/ol/ol-spinner'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import CopySharingLinkButton from '@/features/share-project-modal/components/copy-sharing-link-button'
|
||||
import ErrorMessage from '@/features/share-project-modal/components/error-message'
|
||||
import GiveFeedbackLink from '@/features/share-project-modal/components/give-feedback-link'
|
||||
import classNames from 'classnames'
|
||||
@@ -74,7 +75,7 @@ function ShareProjectModalContentInner({
|
||||
const { t } = useTranslation()
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const [isInvitedPeopleScreen, setIsInvitedPeopleScreen] = useState(false)
|
||||
const { successActionMessage } = useShareProjectContext()
|
||||
const { successActionMessage, projectAccess } = useShareProjectContext()
|
||||
const { isRestrictedTokenMember, isProjectOwner } = useEditorContext()
|
||||
|
||||
return (
|
||||
@@ -135,6 +136,12 @@ function ShareProjectModalContentInner({
|
||||
<div className="d-flex flex-grow-1 flex-wrap gap-2">
|
||||
{isSharingUpdatesEnabled ? (
|
||||
<>
|
||||
{!isInvitedPeopleScreen &&
|
||||
(projectAccess === 'onlyInvitedPeople' ||
|
||||
projectAccess === 'anyoneInXyzWithTheLink' ||
|
||||
projectAccess === 'anyoneWithTheLink') && (
|
||||
<CopySharingLinkButton />
|
||||
)}
|
||||
{successActionMessage && (
|
||||
<div className="ms-auto px-3 align-self-center">
|
||||
<div
|
||||
|
||||
@@ -517,6 +517,7 @@
|
||||
"copy": "Copy",
|
||||
"copy_project": "Copy project",
|
||||
"copy_response": "Copy response",
|
||||
"copy_sharing_link": "Copy sharing link",
|
||||
"copying": "Copying",
|
||||
"cost_summary": "Cost summary",
|
||||
"could_not_connect_to_collaboration_server": "Could not connect to collaboration server",
|
||||
@@ -1464,6 +1465,7 @@
|
||||
"link_account": "Link Account",
|
||||
"link_accounts": "Link accounts",
|
||||
"link_accounts_and_add_email": "Link accounts and add email",
|
||||
"link_copied": "Link copied",
|
||||
"link_institutional_email_get_started": "Link an institutional email address to your account to get started.",
|
||||
"link_sharing": "Link sharing",
|
||||
"link_sharing_is_off_short": "Link sharing is off",
|
||||
|
||||
+70
@@ -1005,6 +1005,10 @@ describe('<ShareProjectModal/>', function () {
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
window.metaAttributesCache.delete('ol-splitTestVariants')
|
||||
})
|
||||
|
||||
it('sets "Via sharing links (legacy)" when `publicAccessLevel` is `tokenBased`', async function () {
|
||||
fetchMock.get(`/project/${shareModalProjectDefaults._id}/tokens`, {})
|
||||
|
||||
@@ -1060,6 +1064,72 @@ describe('<ShareProjectModal/>', function () {
|
||||
|
||||
await screen.findByText('Anyone in your group with the link')
|
||||
})
|
||||
|
||||
describe('copy link button', function () {
|
||||
let clipboardWriteTextStub: sinon.SinonStub
|
||||
|
||||
beforeEach(function () {
|
||||
clipboardWriteTextStub = sinon.stub().resolves()
|
||||
Object.defineProperty(navigator, 'clipboard', {
|
||||
value: { writeText: clipboardWriteTextStub },
|
||||
configurable: true,
|
||||
writable: true,
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
window.metaAttributesCache.delete('ol-splitTestVariants')
|
||||
delete (navigator as any).clipboard
|
||||
})
|
||||
|
||||
it('shows a disabled copy sharing link button when access is "Only invited people"', async function () {
|
||||
fetchMock.get('express:/project/:projectId/sharing-link', 404)
|
||||
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal {...modalProps} />,
|
||||
createContextProps()
|
||||
)
|
||||
|
||||
const copyButton: HTMLButtonElement = await screen.findByRole(
|
||||
'button',
|
||||
{
|
||||
name: /copy sharing link/i,
|
||||
}
|
||||
)
|
||||
expect(copyButton.disabled).to.be.true
|
||||
})
|
||||
|
||||
it('enables the copy sharing link button when access is "Anyone with the link" and copies the correct URL on click', async function () {
|
||||
const sharingLinkToken = 'abc123token'
|
||||
fetchMock.get('express:/project/:projectId/sharing-link', {
|
||||
_id: 'invite-id',
|
||||
token: sharingLinkToken,
|
||||
privileges: 'readAndWrite',
|
||||
})
|
||||
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal {...modalProps} />,
|
||||
createContextProps()
|
||||
)
|
||||
|
||||
const copyButton: HTMLButtonElement = await screen.findByRole(
|
||||
'button',
|
||||
{
|
||||
name: /copy sharing link/i,
|
||||
}
|
||||
)
|
||||
expect(copyButton.disabled).to.be.false
|
||||
|
||||
await userEvent.click(copyButton)
|
||||
|
||||
expect(clipboardWriteTextStub.calledOnce).to.be.true
|
||||
expect(clipboardWriteTextStub.firstCall.args[0]).to.equal(
|
||||
`${window.location.origin}/project/${shareModalProjectDefaults._id}/share#${sharingLinkToken}`
|
||||
)
|
||||
|
||||
await screen.findByText(/link copied/i)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('allows an email address to be selected, removed, then re-added', async function () {
|
||||
|
||||
Reference in New Issue
Block a user