mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #6236 from overleaf/ta-project-context-strict
Strict Project Context GitOrigin-RevId: a0f7f2b3dcb29fbd0102dcb920cf5424a921d583
This commit is contained in:
parent
24bd557485
commit
6319455e91
16 changed files with 162 additions and 157 deletions
|
@ -75,7 +75,7 @@ function fileTreeSelectableReadOnlyReducer(selectedEntityIds, action) {
|
|||
}
|
||||
|
||||
export function FileTreeSelectableProvider({ onSelect, children }) {
|
||||
const { _id: projectId, rootDoc_id: rootDocId } = useProjectContext(
|
||||
const { _id: projectId, rootDocId } = useProjectContext(
|
||||
projectContextPropTypes
|
||||
)
|
||||
const { permissionsLevel } = useEditorContext(editorContextPropTypes)
|
||||
|
@ -187,7 +187,7 @@ FileTreeSelectableProvider.propTypes = {
|
|||
|
||||
const projectContextPropTypes = {
|
||||
_id: PropTypes.string.isRequired,
|
||||
rootDoc_id: PropTypes.string,
|
||||
rootDocId: PropTypes.string,
|
||||
}
|
||||
|
||||
const editorContextPropTypes = {
|
||||
|
|
|
@ -15,7 +15,8 @@ const searchParams = new URLSearchParams(window.location.search)
|
|||
|
||||
export default class DocumentCompiler {
|
||||
constructor({
|
||||
project,
|
||||
projectId,
|
||||
rootDocId,
|
||||
setChangedAt,
|
||||
setCompiling,
|
||||
setData,
|
||||
|
@ -24,7 +25,8 @@ export default class DocumentCompiler {
|
|||
cleanupCompileResult,
|
||||
signal,
|
||||
}) {
|
||||
this.project = project
|
||||
this.projectId = projectId
|
||||
this.rootDocId = rootDocId
|
||||
this.setChangedAt = setChangedAt
|
||||
this.setCompiling = setCompiling
|
||||
this.setData = setData
|
||||
|
@ -84,7 +86,7 @@ export default class DocumentCompiler {
|
|||
const t0 = performance.now()
|
||||
|
||||
const data = await postJSON(
|
||||
`/project/${this.project._id}/compile?${params}`,
|
||||
`/project/${this.projectId}/compile?${params}`,
|
||||
{
|
||||
body: {
|
||||
rootDoc_id: this.getRootDocOverrideId(),
|
||||
|
@ -122,7 +124,7 @@ export default class DocumentCompiler {
|
|||
// if it contains "\documentclass" then use this as the root doc
|
||||
getRootDocOverrideId() {
|
||||
// only override when not in the root doc itself
|
||||
if (this.currentDoc.doc_id !== this.project.rootDoc_id) {
|
||||
if (this.currentDoc.doc_id !== this.rootDocId) {
|
||||
const snapshot = this.currentDoc.getSnapshot()
|
||||
|
||||
if (snapshot && isMainFile(snapshot)) {
|
||||
|
@ -177,7 +179,7 @@ export default class DocumentCompiler {
|
|||
|
||||
const params = this.buildPostCompileParams()
|
||||
|
||||
return postJSON(`/project/${this.project._id}/compile/stop?${params}`, {
|
||||
return postJSON(`/project/${this.projectId}/compile/stop?${params}`, {
|
||||
signal: this.signal,
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -193,7 +195,7 @@ export default class DocumentCompiler {
|
|||
clearCache() {
|
||||
const params = this.buildPostCompileParams()
|
||||
|
||||
return deleteJSON(`/project/${this.project._id}/output?${params}`, {
|
||||
return deleteJSON(`/project/${this.projectId}/output?${params}`, {
|
||||
signal: this.signal,
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
|
|
|
@ -20,11 +20,11 @@ export default function AddCollaborators() {
|
|||
|
||||
const { updateProject, setInFlight, setError } = useShareProjectContext()
|
||||
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, members, invites } = useProjectContext()
|
||||
|
||||
const currentMemberEmails = useMemo(
|
||||
() => (project.members || []).map(member => member.email).sort(),
|
||||
[project.members]
|
||||
() => (members || []).map(member => member.email).sort(),
|
||||
[members]
|
||||
)
|
||||
|
||||
const nonMemberContacts = useMemo(() => {
|
||||
|
@ -73,14 +73,14 @@ export default function AddCollaborators() {
|
|||
let data
|
||||
|
||||
try {
|
||||
const invite = (project.invites || []).find(
|
||||
const invite = (invites || []).find(
|
||||
invite => invite.email === normalisedEmail
|
||||
)
|
||||
|
||||
if (invite) {
|
||||
data = await resendInvite(project, invite)
|
||||
data = await resendInvite(projectId, invite)
|
||||
} else {
|
||||
data = await sendInvite(project, email, privileges)
|
||||
data = await sendInvite(projectId, email, privileges)
|
||||
}
|
||||
} catch (error) {
|
||||
setInFlight(false)
|
||||
|
@ -98,15 +98,15 @@ export default function AddCollaborators() {
|
|||
setInFlight(false)
|
||||
} else if (data.invite) {
|
||||
updateProject({
|
||||
invites: project.invites.concat(data.invite),
|
||||
invites: invites.concat(data.invite),
|
||||
})
|
||||
} else if (data.users) {
|
||||
updateProject({
|
||||
members: project.members.concat(data.users),
|
||||
members: members.concat(data.users),
|
||||
})
|
||||
} else if (data.user) {
|
||||
updateProject({
|
||||
members: project.members.concat(data.user),
|
||||
members: members.concat(data.user),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ export default function EditMember({ member }) {
|
|||
}, [member.privileges])
|
||||
|
||||
const { updateProject, monitorRequest } = useShareProjectContext()
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, members } = useProjectContext()
|
||||
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault()
|
||||
|
@ -36,12 +36,12 @@ export default function EditMember({ member }) {
|
|||
setConfirmingOwnershipTransfer(true)
|
||||
} else {
|
||||
monitorRequest(() =>
|
||||
updateMember(project, member, {
|
||||
updateMember(projectId, member, {
|
||||
privilegeLevel: privileges,
|
||||
})
|
||||
).then(() => {
|
||||
updateProject({
|
||||
members: project.members.map(item =>
|
||||
members: members.map(item =>
|
||||
item._id === member._id ? { ...item, privileges } : item
|
||||
),
|
||||
})
|
||||
|
@ -118,16 +118,18 @@ SelectPrivilege.propTypes = {
|
|||
function RemoveMemberAction({ member }) {
|
||||
const { t } = useTranslation()
|
||||
const { updateProject, monitorRequest } = useShareProjectContext()
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, members } = useProjectContext()
|
||||
|
||||
function handleClick(event) {
|
||||
event.preventDefault()
|
||||
|
||||
monitorRequest(() => removeMemberFromProject(project, member)).then(() => {
|
||||
updateProject({
|
||||
members: project.members.filter(existing => existing !== member),
|
||||
})
|
||||
})
|
||||
monitorRequest(() => removeMemberFromProject(projectId, member)).then(
|
||||
() => {
|
||||
updateProject({
|
||||
members: members.filter(existing => existing !== member),
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -41,20 +41,20 @@ Invite.propTypes = {
|
|||
|
||||
function ResendInvite({ invite }) {
|
||||
const { monitorRequest } = useShareProjectContext()
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId } = useProjectContext()
|
||||
|
||||
// const buttonRef = useRef(null)
|
||||
//
|
||||
const handleClick = useCallback(
|
||||
() =>
|
||||
monitorRequest(() => resendInvite(project, invite)).finally(() => {
|
||||
monitorRequest(() => resendInvite(projectId, invite)).finally(() => {
|
||||
// NOTE: disabled as react-bootstrap v0.33.1 isn't forwarding the ref to the `button`
|
||||
// if (buttonRef.current) {
|
||||
// buttonRef.current.blur()
|
||||
// }
|
||||
document.activeElement.blur()
|
||||
}),
|
||||
[invite, monitorRequest, project]
|
||||
[invite, monitorRequest, projectId]
|
||||
)
|
||||
|
||||
return (
|
||||
|
@ -75,14 +75,14 @@ ResendInvite.propTypes = {
|
|||
function RevokeInvite({ invite }) {
|
||||
const { t } = useTranslation()
|
||||
const { updateProject, monitorRequest } = useShareProjectContext()
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, invites } = useProjectContext()
|
||||
|
||||
function handleClick(event) {
|
||||
event.preventDefault()
|
||||
|
||||
monitorRequest(() => revokeInvite(project, invite)).then(() => {
|
||||
monitorRequest(() => revokeInvite(projectId, invite)).then(() => {
|
||||
updateProject({
|
||||
invites: project.invites.filter(existing => existing !== invite),
|
||||
invites: invites.filter(existing => existing !== invite),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,27 +14,29 @@ export default function LinkSharing() {
|
|||
|
||||
const { monitorRequest } = useShareProjectContext()
|
||||
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, publicAccessLevel } = useProjectContext()
|
||||
|
||||
// set the access level of a project
|
||||
const setAccessLevel = useCallback(
|
||||
publicAccesLevel => {
|
||||
newPublicAccessLevel => {
|
||||
setInflight(true)
|
||||
monitorRequest(() => setProjectAccessLevel(project, publicAccesLevel))
|
||||
monitorRequest(() =>
|
||||
setProjectAccessLevel(projectId, newPublicAccessLevel)
|
||||
)
|
||||
.then(() => {
|
||||
// NOTE: not calling `updateProject` here as it receives data via
|
||||
// project:publicAccessLevel:changed and project:tokens:changed
|
||||
// over the websocket connection
|
||||
// TODO: eventTracking.sendMB('project-make-token-based') when publicAccesLevel is 'tokenBased'
|
||||
// TODO: eventTracking.sendMB('project-make-token-based') when newPublicAccessLevel is 'tokenBased'
|
||||
})
|
||||
.finally(() => {
|
||||
setInflight(false)
|
||||
})
|
||||
},
|
||||
[monitorRequest, project]
|
||||
[monitorRequest, projectId]
|
||||
)
|
||||
|
||||
switch (project.publicAccesLevel) {
|
||||
switch (publicAccessLevel) {
|
||||
// Private (with token-access available)
|
||||
case 'private':
|
||||
return (
|
||||
|
@ -56,7 +58,7 @@ export default function LinkSharing() {
|
|||
return (
|
||||
<LegacySharing
|
||||
setAccessLevel={setAccessLevel}
|
||||
accessLevel={project.publicAccesLevel}
|
||||
accessLevel={publicAccessLevel}
|
||||
inflight={inflight}
|
||||
/>
|
||||
)
|
||||
|
@ -96,7 +98,7 @@ PrivateSharing.propTypes = {
|
|||
}
|
||||
|
||||
function TokenBasedSharing({ setAccessLevel, inflight }) {
|
||||
const project = useProjectContext()
|
||||
const { tokens } = useProjectContext()
|
||||
|
||||
return (
|
||||
<Row className="public-access-level">
|
||||
|
@ -122,7 +124,7 @@ function TokenBasedSharing({ setAccessLevel, inflight }) {
|
|||
<Trans i18nKey="anyone_with_link_can_edit" />
|
||||
</strong>
|
||||
<AccessToken
|
||||
token={project?.tokens?.readAndWrite}
|
||||
token={tokens?.readAndWrite}
|
||||
path="/"
|
||||
tooltipId="tooltip-copy-link-rw"
|
||||
/>
|
||||
|
@ -132,7 +134,7 @@ function TokenBasedSharing({ setAccessLevel, inflight }) {
|
|||
<Trans i18nKey="anyone_with_link_can_view" />
|
||||
</strong>
|
||||
<AccessToken
|
||||
token={project?.tokens?.readOnly}
|
||||
token={tokens?.readOnly}
|
||||
path="/read/"
|
||||
tooltipId="tooltip-copy-link-ro"
|
||||
/>
|
||||
|
@ -181,7 +183,7 @@ LegacySharing.propTypes = {
|
|||
}
|
||||
|
||||
export function ReadOnlyTokenLink() {
|
||||
const project = useProjectContext()
|
||||
const { tokens } = useProjectContext()
|
||||
|
||||
return (
|
||||
<Row className="public-access-level">
|
||||
|
@ -191,7 +193,7 @@ export function ReadOnlyTokenLink() {
|
|||
<Trans i18nKey="anyone_with_link_can_view" />
|
||||
</strong>
|
||||
<AccessToken
|
||||
token={project?.tokens?.readOnly}
|
||||
token={tokens?.readOnly}
|
||||
path="/read/"
|
||||
tooltipId="tooltip-copy-link-ro"
|
||||
/>
|
||||
|
|
|
@ -3,11 +3,11 @@ import { Col, Row } from 'react-bootstrap'
|
|||
import { Trans } from 'react-i18next'
|
||||
|
||||
export default function OwnerInfo() {
|
||||
const project = useProjectContext()
|
||||
const { owner } = useProjectContext()
|
||||
|
||||
return (
|
||||
<Row className="project-member">
|
||||
<Col xs={7}>{project.owner?.email}</Col>
|
||||
<Col xs={7}>{owner?.email}</Col>
|
||||
<Col xs={3} className="text-left">
|
||||
<Trans i18nKey="owner" />
|
||||
</Col>
|
||||
|
|
|
@ -4,12 +4,12 @@ import { Trans } from 'react-i18next'
|
|||
import { useProjectContext } from '../../../shared/context/project-context'
|
||||
|
||||
export default function SendInvitesNotice() {
|
||||
const project = useProjectContext()
|
||||
const { publicAccessLevel } = useProjectContext()
|
||||
|
||||
return (
|
||||
<Row className="public-access-level public-access-level--notice">
|
||||
<Col xs={12} className="text-center">
|
||||
<AccessLevel level={project.publicAccesLevel} />
|
||||
<AccessLevel level={publicAccessLevel} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
|
|
|
@ -5,24 +5,21 @@ import AddCollaboratorsUpgrade from './add-collaborators-upgrade'
|
|||
import { useProjectContext } from '../../../shared/context/project-context'
|
||||
|
||||
export default function SendInvites() {
|
||||
const project = useProjectContext()
|
||||
const { members, invites, features } = useProjectContext()
|
||||
|
||||
// whether the project has not reached the collaborator limit
|
||||
const canAddCollaborators = useMemo(() => {
|
||||
if (!project) {
|
||||
if (!features) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (project.features.collaborators === -1) {
|
||||
if (features.collaborators === -1) {
|
||||
// infinite collaborators
|
||||
return true
|
||||
}
|
||||
|
||||
return (
|
||||
project.members.length + project.invites.length <
|
||||
project.features.collaborators
|
||||
)
|
||||
}, [project])
|
||||
return members.length + invites.length < features.collaborators
|
||||
}, [members, invites, features])
|
||||
|
||||
return (
|
||||
<Row className="invite-controls">
|
||||
|
|
|
@ -18,7 +18,7 @@ export default function ShareModalBody() {
|
|||
splitTestVariants: PropTypes.object,
|
||||
})
|
||||
|
||||
const project = useProjectContext()
|
||||
const { invites, members } = useProjectContext()
|
||||
|
||||
switch (splitTestVariants['project-share-modal-paywall']) {
|
||||
case 'new-copy-top':
|
||||
|
@ -35,7 +35,7 @@ export default function ShareModalBody() {
|
|||
|
||||
<OwnerInfo />
|
||||
|
||||
{project.members.map(member =>
|
||||
{members.map(member =>
|
||||
isAdmin ? (
|
||||
<EditMember key={member._id} member={member} />
|
||||
) : (
|
||||
|
@ -43,7 +43,7 @@ export default function ShareModalBody() {
|
|||
)
|
||||
)}
|
||||
|
||||
{project.invites.map(invite => (
|
||||
{invites.map(invite => (
|
||||
<Invite key={invite._id} invite={invite} isAdmin={isAdmin} />
|
||||
))}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export default function ShareModalBody() {
|
|||
<>
|
||||
<OwnerInfo />
|
||||
|
||||
{project.members.map(member =>
|
||||
{members.map(member =>
|
||||
isAdmin ? (
|
||||
<EditMember key={member._id} member={member} />
|
||||
) : (
|
||||
|
@ -72,7 +72,7 @@ export default function ShareModalBody() {
|
|||
)
|
||||
)}
|
||||
|
||||
{project.invites.map(invite => (
|
||||
{invites.map(invite => (
|
||||
<Invite key={invite._id} invite={invite} isAdmin={isAdmin} />
|
||||
))}
|
||||
|
||||
|
@ -99,7 +99,7 @@ export default function ShareModalBody() {
|
|||
|
||||
<OwnerInfo />
|
||||
|
||||
{project.members.map(member =>
|
||||
{members.map(member =>
|
||||
isAdmin ? (
|
||||
<EditMember key={member._id} member={member} />
|
||||
) : (
|
||||
|
@ -107,7 +107,7 @@ export default function ShareModalBody() {
|
|||
)
|
||||
)}
|
||||
|
||||
{project.invites.map(invite => (
|
||||
{invites.map(invite => (
|
||||
<Invite key={invite._id} invite={invite} isAdmin={isAdmin} />
|
||||
))}
|
||||
|
||||
|
|
|
@ -7,7 +7,10 @@ import React, {
|
|||
} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ShareProjectModalContent from './share-project-modal-content'
|
||||
import { useProjectContext } from '../../../shared/context/project-context'
|
||||
import {
|
||||
useProjectContext,
|
||||
projectShape,
|
||||
} from '../../../shared/context/project-context'
|
||||
import { useSplitTestContext } from '../../../shared/context/split-test-context'
|
||||
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||
|
||||
|
@ -37,32 +40,6 @@ export function useShareProjectContext() {
|
|||
return context
|
||||
}
|
||||
|
||||
const projectShape = {
|
||||
_id: PropTypes.string.isRequired,
|
||||
members: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
invites: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
name: PropTypes.string,
|
||||
features: PropTypes.shape({
|
||||
collaborators: PropTypes.number,
|
||||
}),
|
||||
publicAccesLevel: PropTypes.string,
|
||||
tokens: PropTypes.shape({
|
||||
readOnly: PropTypes.string,
|
||||
readAndWrite: PropTypes.string,
|
||||
}),
|
||||
owner: PropTypes.shape({
|
||||
email: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
const ShareProjectModal = React.memo(function ShareProjectModal({
|
||||
handleHide,
|
||||
show,
|
||||
|
|
|
@ -12,13 +12,13 @@ export default function TransferOwnershipModal({ member, cancel }) {
|
|||
const [inflight, setInflight] = useState(false)
|
||||
const [error, setError] = useState(false)
|
||||
|
||||
const project = useProjectContext()
|
||||
const { _id: projectId, name: projectName } = useProjectContext()
|
||||
|
||||
function confirm() {
|
||||
setError(false)
|
||||
setInflight(true)
|
||||
|
||||
transferProjectOwnership(project, member)
|
||||
transferProjectOwnership(projectId, member)
|
||||
.then(() => {
|
||||
reload()
|
||||
})
|
||||
|
@ -39,7 +39,7 @@ export default function TransferOwnershipModal({ member, cancel }) {
|
|||
<p>
|
||||
<Trans
|
||||
i18nKey="project_ownership_transfer_confirmation_1"
|
||||
values={{ user: member.email, project: project.name }}
|
||||
values={{ user: member.email, project: projectName }}
|
||||
components={[<strong key="strong-1" />, <strong key="strong-2" />]}
|
||||
/>
|
||||
</p>
|
||||
|
|
|
@ -45,7 +45,7 @@ export default App.controller(
|
|||
|
||||
ide.socket.on('project:membership:changed', data => {
|
||||
if (data.members) {
|
||||
listProjectMembers($scope.project)
|
||||
listProjectMembers($scope.project._id)
|
||||
.then(({ members }) => {
|
||||
if (members) {
|
||||
$scope.$applyAsync(() => {
|
||||
|
@ -59,7 +59,7 @@ export default App.controller(
|
|||
}
|
||||
|
||||
if (data.invites) {
|
||||
listProjectInvites($scope.project)
|
||||
listProjectInvites($scope.project._id)
|
||||
.then(({ invites }) => {
|
||||
if (invites) {
|
||||
$scope.$applyAsync(() => {
|
||||
|
|
|
@ -6,11 +6,11 @@ import {
|
|||
} from '../../../infrastructure/fetch-json'
|
||||
import { executeV2Captcha } from './captcha'
|
||||
|
||||
export function sendInvite(project, email, privileges) {
|
||||
export function sendInvite(projectId, email, privileges) {
|
||||
return executeV2Captcha(
|
||||
window.ExposedSettings.recaptchaDisabled?.invite
|
||||
).then(grecaptchaResponse => {
|
||||
return postJSON(`/project/${project._id}/invite`, {
|
||||
return postJSON(`/project/${projectId}/invite`, {
|
||||
body: {
|
||||
email, // TODO: normalisedEmail?
|
||||
privileges,
|
||||
|
@ -20,48 +20,42 @@ export function sendInvite(project, email, privileges) {
|
|||
})
|
||||
}
|
||||
|
||||
export function resendInvite(project, invite) {
|
||||
return postJSON(`/project/${project._id}/invite/${invite._id}/resend`)
|
||||
export function resendInvite(projectId, invite) {
|
||||
return postJSON(`/project/${projectId}/invite/${invite._id}/resend`)
|
||||
}
|
||||
|
||||
export function revokeInvite(project, invite) {
|
||||
return deleteJSON(`/project/${project._id}/invite/${invite._id}`)
|
||||
export function revokeInvite(projectId, invite) {
|
||||
return deleteJSON(`/project/${projectId}/invite/${invite._id}`)
|
||||
}
|
||||
|
||||
export function updateMember(project, member, data) {
|
||||
return putJSON(`/project/${project._id}/users/${member._id}`, {
|
||||
export function updateMember(projectId, member, data) {
|
||||
return putJSON(`/project/${projectId}/users/${member._id}`, {
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
|
||||
export function removeMemberFromProject(project, member) {
|
||||
return deleteJSON(`/project/${project._id}/users/${member._id}`)
|
||||
export function removeMemberFromProject(projectId, member) {
|
||||
return deleteJSON(`/project/${projectId}/users/${member._id}`)
|
||||
}
|
||||
|
||||
export function transferProjectOwnership(project, member) {
|
||||
return postJSON(`/project/${project._id}/transfer-ownership`, {
|
||||
export function transferProjectOwnership(projectId, member) {
|
||||
return postJSON(`/project/${projectId}/transfer-ownership`, {
|
||||
body: {
|
||||
user_id: member._id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function setProjectAccessLevel(project, publicAccessLevel) {
|
||||
return postJSON(`/project/${project._id}/settings/admin`, {
|
||||
export function setProjectAccessLevel(projectId, publicAccessLevel) {
|
||||
return postJSON(`/project/${projectId}/settings/admin`, {
|
||||
body: { publicAccessLevel },
|
||||
})
|
||||
}
|
||||
|
||||
// export function updateProjectAdminSettings(project, data) {
|
||||
// return postJSON(`/project/${project._id}/settings/admin`, {
|
||||
// body: data
|
||||
// })
|
||||
// }
|
||||
|
||||
export function listProjectMembers(project) {
|
||||
return getJSON(`/project/${project._id}/members`)
|
||||
export function listProjectMembers(projectId) {
|
||||
return getJSON(`/project/${projectId}/members`)
|
||||
}
|
||||
|
||||
export function listProjectInvites(project) {
|
||||
return getJSON(`/project/${project._id}/invites`)
|
||||
export function listProjectInvites(projectId) {
|
||||
return getJSON(`/project/${projectId}/invites`)
|
||||
}
|
||||
|
|
|
@ -64,9 +64,7 @@ export function CompileProvider({ children }) {
|
|||
|
||||
const { hasPremiumCompile, isProjectOwner } = useEditorContext()
|
||||
|
||||
const project = useProjectContext()
|
||||
|
||||
const projectId = project._id
|
||||
const { _id: projectId, rootDocId } = useProjectContext()
|
||||
|
||||
// whether a compile is in progress
|
||||
const [compiling, setCompiling] = useState(false)
|
||||
|
@ -169,7 +167,8 @@ export function CompileProvider({ children }) {
|
|||
// the document compiler
|
||||
const [compiler] = useState(() => {
|
||||
return new DocumentCompiler({
|
||||
project,
|
||||
projectId,
|
||||
rootDocId,
|
||||
setChangedAt,
|
||||
setCompiling,
|
||||
setData,
|
||||
|
|
|
@ -4,39 +4,41 @@ import useScopeValue from '../hooks/use-scope-value'
|
|||
|
||||
const ProjectContext = createContext()
|
||||
|
||||
ProjectContext.Provider.propTypes = {
|
||||
value: PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
rootDoc_id: PropTypes.string,
|
||||
members: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
invites: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
features: PropTypes.shape({
|
||||
collaborators: PropTypes.number,
|
||||
compileGroup: PropTypes.oneOf(['alpha', 'standard', 'priority']),
|
||||
trackChangesVisible: PropTypes.bool,
|
||||
references: PropTypes.bool,
|
||||
mendeley: PropTypes.bool,
|
||||
zotero: PropTypes.bool,
|
||||
}),
|
||||
publicAccesLevel: PropTypes.string,
|
||||
tokens: PropTypes.shape({
|
||||
readOnly: PropTypes.string,
|
||||
readAndWrite: PropTypes.string,
|
||||
}),
|
||||
owner: PropTypes.shape({
|
||||
export const projectShape = {
|
||||
_id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
rootDocId: PropTypes.string,
|
||||
members: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
}),
|
||||
})
|
||||
),
|
||||
invites: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
features: PropTypes.shape({
|
||||
collaborators: PropTypes.number,
|
||||
compileGroup: PropTypes.oneOf(['alpha', 'standard', 'priority']),
|
||||
trackChangesVisible: PropTypes.bool,
|
||||
references: PropTypes.bool,
|
||||
mendeley: PropTypes.bool,
|
||||
zotero: PropTypes.bool,
|
||||
}),
|
||||
publicAccessLevel: PropTypes.string,
|
||||
tokens: PropTypes.shape({
|
||||
readOnly: PropTypes.string,
|
||||
readAndWrite: PropTypes.string,
|
||||
}),
|
||||
owner: PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
ProjectContext.Provider.propTypes = {
|
||||
value: PropTypes.shape(projectShape),
|
||||
}
|
||||
|
||||
export function useProjectContext(propTypes) {
|
||||
|
@ -70,12 +72,42 @@ const projectFallback = {
|
|||
export function ProjectProvider({ children }) {
|
||||
const [project] = useScopeValue('project', true)
|
||||
|
||||
const {
|
||||
_id,
|
||||
name,
|
||||
rootDoc_id: rootDocId,
|
||||
members,
|
||||
invites,
|
||||
features,
|
||||
publicAccesLevel: publicAccessLevel,
|
||||
tokens,
|
||||
owner,
|
||||
} = project || projectFallback
|
||||
|
||||
const value = useMemo(() => {
|
||||
return {
|
||||
...projectFallback,
|
||||
...project,
|
||||
_id,
|
||||
name,
|
||||
rootDocId,
|
||||
members,
|
||||
invites,
|
||||
features,
|
||||
publicAccessLevel,
|
||||
tokens,
|
||||
owner,
|
||||
}
|
||||
}, [project])
|
||||
}, [
|
||||
_id,
|
||||
name,
|
||||
rootDocId,
|
||||
members,
|
||||
invites,
|
||||
features,
|
||||
publicAccessLevel,
|
||||
tokens,
|
||||
owner,
|
||||
])
|
||||
|
||||
return (
|
||||
<ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue