2021-03-12 05:23:46 -05:00
|
|
|
import React, { useEffect } from 'react'
|
|
|
|
import ShareProjectModal from '../js/features/share-project-modal/components/share-project-modal'
|
2021-06-03 09:44:23 -04:00
|
|
|
import { ContextRoot } from '../js/shared/context/root-context'
|
2021-05-11 10:25:22 -04:00
|
|
|
import useFetchMock from './hooks/use-fetch-mock'
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
export const LinkSharingOff = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'private',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const LinkSharingOn = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'tokenBased',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const LinkSharingLoading = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
|
|
|
publicAccesLevel: 'tokenBased',
|
2021-04-27 03:52:58 -04:00
|
|
|
tokens: undefined,
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const NonAdminLinkSharingOff = args => {
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'private',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
2021-03-31 06:44:20 -04:00
|
|
|
<ShareProjectModal
|
|
|
|
{...args}
|
|
|
|
isAdmin={false}
|
|
|
|
ide={ideWithProject(project)}
|
|
|
|
/>
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const NonAdminLinkSharingOn = args => {
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'tokenBased',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
2021-03-31 06:44:20 -04:00
|
|
|
<ShareProjectModal
|
|
|
|
{...args}
|
|
|
|
isAdmin={false}
|
|
|
|
ide={ideWithProject(project)}
|
|
|
|
/>
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const RestrictedTokenMember = args => {
|
2021-06-03 09:44:23 -04:00
|
|
|
// Override isRestrictedTokenMember to be true, then revert it back to the
|
|
|
|
// original value on unmount
|
|
|
|
// Currently this is necessary because the context value is set from window,
|
|
|
|
// however in the future we should change this to set via props
|
|
|
|
const originalIsRestrictedTokenMember = window.isRestrictedTokenMember
|
2021-03-12 05:23:46 -05:00
|
|
|
window.isRestrictedTokenMember = true
|
|
|
|
useEffect(() => {
|
|
|
|
return () => {
|
2021-06-03 09:44:23 -04:00
|
|
|
window.isRestrictedTokenMember = originalIsRestrictedTokenMember
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
2021-06-03 09:44:23 -04:00
|
|
|
})
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'tokenBased',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const LegacyLinkSharingReadAndWrite = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'readAndWrite',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const LegacyLinkSharingReadOnly = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
2021-04-27 03:52:58 -04:00
|
|
|
publicAccesLevel: 'readOnly',
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const LimitedCollaborators = args => {
|
2021-05-11 10:25:22 -04:00
|
|
|
useFetchMock(setupFetchMock)
|
2021-03-12 05:23:46 -05:00
|
|
|
|
|
|
|
const project = {
|
|
|
|
...args.project,
|
|
|
|
features: {
|
|
|
|
...args.project.features,
|
2021-04-27 03:52:58 -04:00
|
|
|
collaborators: 3,
|
|
|
|
},
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
2021-06-03 09:44:23 -04:00
|
|
|
return renderWithContext(
|
|
|
|
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
|
|
|
)
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const project = {
|
|
|
|
_id: 'a-project',
|
|
|
|
name: 'A Project',
|
|
|
|
features: {
|
2021-04-27 03:52:58 -04:00
|
|
|
collaborators: -1, // unlimited
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
publicAccesLevel: 'private',
|
|
|
|
tokens: {
|
|
|
|
readOnly: 'ro-token',
|
2021-04-27 03:52:58 -04:00
|
|
|
readAndWrite: 'rw-token',
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
owner: {
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'stories@overleaf.com',
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
members: [
|
|
|
|
{
|
|
|
|
_id: 'viewer-member',
|
|
|
|
type: 'user',
|
|
|
|
privileges: 'readOnly',
|
|
|
|
name: 'Viewer User',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'viewer@example.com',
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
_id: 'author-member',
|
|
|
|
type: 'user',
|
|
|
|
privileges: 'readAndWrite',
|
|
|
|
name: 'Author User',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'author@example.com',
|
|
|
|
},
|
2021-03-12 05:23:46 -05:00
|
|
|
],
|
|
|
|
invites: [
|
|
|
|
{
|
|
|
|
_id: 'test-invite-1',
|
|
|
|
privileges: 'readOnly',
|
|
|
|
name: 'Invited Viewer',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'invited-viewer@example.com',
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
_id: 'test-invite-2',
|
|
|
|
privileges: 'readAndWrite',
|
|
|
|
name: 'Invited Author',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'invited-author@example.com',
|
|
|
|
},
|
|
|
|
],
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export default {
|
2021-03-25 06:11:45 -04:00
|
|
|
title: 'Modals / Share Project',
|
2021-03-12 05:23:46 -05:00
|
|
|
component: ShareProjectModal,
|
|
|
|
args: {
|
|
|
|
show: true,
|
|
|
|
animation: false,
|
|
|
|
isAdmin: true,
|
|
|
|
user: {},
|
2021-04-27 03:52:58 -04:00
|
|
|
project,
|
2021-03-12 05:23:46 -05:00
|
|
|
},
|
|
|
|
argTypes: {
|
2021-04-27 03:52:58 -04:00
|
|
|
handleHide: { action: 'hide' },
|
|
|
|
},
|
2021-03-12 05:23:46 -05:00
|
|
|
}
|
2021-06-03 09:44:23 -04:00
|
|
|
|
|
|
|
// Unfortunately, we cannot currently use decorators here, since we need to
|
|
|
|
// set a value on window, before the contexts are rendered.
|
|
|
|
// When using decorators, the contexts are rendered before the story, so we
|
|
|
|
// don't have the opportunity to set the window value first.
|
|
|
|
function renderWithContext(Story) {
|
|
|
|
return (
|
|
|
|
<ContextRoot ide={window._ide} settings={{}}>
|
|
|
|
{Story}
|
|
|
|
</ContextRoot>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const contacts = [
|
|
|
|
// user with edited name
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
email: 'test-user@example.com',
|
|
|
|
first_name: 'Test',
|
|
|
|
last_name: 'User',
|
|
|
|
name: 'Test User',
|
|
|
|
},
|
|
|
|
// user with default name (email prefix)
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
email: 'test@example.com',
|
|
|
|
first_name: 'test',
|
|
|
|
},
|
|
|
|
// no last name
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
first_name: 'Eratosthenes',
|
|
|
|
email: 'eratosthenes@example.com',
|
|
|
|
},
|
|
|
|
// more users
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
first_name: 'Claudius',
|
|
|
|
last_name: 'Ptolemy',
|
|
|
|
email: 'ptolemy@example.com',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
first_name: 'Abd al-Rahman',
|
|
|
|
last_name: 'Al-Sufi',
|
|
|
|
email: 'al-sufi@example.com',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'user',
|
|
|
|
first_name: 'Nicolaus',
|
|
|
|
last_name: 'Copernicus',
|
|
|
|
email: 'copernicus@example.com',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
function setupFetchMock(fetchMock) {
|
|
|
|
const delay = 1000
|
|
|
|
|
|
|
|
fetchMock
|
|
|
|
// list contacts
|
|
|
|
.get('express:/user/contacts', { contacts }, { delay })
|
|
|
|
// change privacy setting
|
|
|
|
.post('express:/project/:projectId/settings/admin', 200, { delay })
|
|
|
|
// update project member (e.g. set privilege level)
|
|
|
|
.put('express:/project/:projectId/users/:userId', 200, { delay })
|
|
|
|
// remove project member
|
|
|
|
.delete('express:/project/:projectId/users/:userId', 200, { delay })
|
|
|
|
// transfer ownership
|
|
|
|
.post('express:/project/:projectId/transfer-ownership', 200, {
|
|
|
|
delay,
|
|
|
|
})
|
|
|
|
// send invite
|
|
|
|
.post('express:/project/:projectId/invite', 200, { delay })
|
|
|
|
// delete invite
|
|
|
|
.delete('express:/project/:projectId/invite/:inviteId', 204, {
|
|
|
|
delay,
|
|
|
|
})
|
|
|
|
// resend invite
|
|
|
|
.post('express:/project/:projectId/invite/:inviteId/resend', 200, {
|
|
|
|
delay,
|
|
|
|
})
|
|
|
|
// send analytics event
|
|
|
|
.post('express:/event/:key', 200)
|
|
|
|
}
|
|
|
|
|
|
|
|
function ideWithProject(project) {
|
|
|
|
return {
|
|
|
|
$scope: {
|
|
|
|
$watch: () => () => {},
|
|
|
|
$applyAsync: () => {},
|
|
|
|
project,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|