mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #4140 from overleaf/ae-react-share-modal
Remove Angular share modal code GitOrigin-RevId: 136b10c7b9768f2d8de13e48b16fd71947506624
This commit is contained in:
parent
9130c37337
commit
cce0051be6
16 changed files with 13 additions and 1997 deletions
|
@ -887,10 +887,6 @@ const ProjectController = {
|
|||
'new_navigation_ui',
|
||||
user.alphaProgram
|
||||
),
|
||||
showReactShareModal: shouldDisplayFeature(
|
||||
'new_share_modal_ui',
|
||||
true
|
||||
),
|
||||
showReactDropboxModal: shouldDisplayFeature(
|
||||
'new_dropbox_modal_ui',
|
||||
user.betaProgram
|
||||
|
|
|
@ -81,7 +81,6 @@ block content
|
|||
else
|
||||
include ./editor/header
|
||||
|
||||
include ./editor/share
|
||||
!= moduleIncludes("publish:body", locals)
|
||||
|
||||
include ./editor/history/toolbarV2.pug
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
div(ng-controller=showReactShareModal ? 'ReactShareProjectModalController': 'ShareController')
|
||||
if showReactShareModal
|
||||
share-project-modal(
|
||||
handle-hide="handleHide"
|
||||
show="show"
|
||||
is-admin="isAdmin"
|
||||
)
|
||||
div(ng-controller="ReactShareProjectModalController")
|
||||
share-project-modal(
|
||||
handle-hide="handleHide"
|
||||
show="show"
|
||||
is-admin="isAdmin"
|
||||
)
|
||||
|
||||
div(ng-controller="EditorNavigationToolbarController")
|
||||
editor-navigation-toolbar-root(
|
||||
|
|
|
@ -119,17 +119,16 @@ header.toolbar.toolbar-header.toolbar-with-labels(
|
|||
a.btn.btn-full-height(
|
||||
href
|
||||
ng-click="openShareProjectModal(permissions.admin);"
|
||||
ng-controller=(showReactShareModal ? 'ReactShareProjectModalController': 'ShareController')
|
||||
ng-controller="ReactShareProjectModalController"
|
||||
)
|
||||
i.fa.fa-fw.fa-group
|
||||
p.toolbar-label #{translate("share")}
|
||||
|
||||
if showReactShareModal
|
||||
share-project-modal(
|
||||
handle-hide="handleHide"
|
||||
show="show"
|
||||
is-admin="isAdmin"
|
||||
)
|
||||
share-project-modal(
|
||||
handle-hide="handleHide"
|
||||
show="show"
|
||||
is-admin="isAdmin"
|
||||
)
|
||||
!= moduleIncludes('publish:button', locals)
|
||||
|
||||
if !isRestrictedTokenMember
|
||||
|
|
|
@ -1,287 +0,0 @@
|
|||
script(type='text/ng-template', id='shareProjectModalTemplate')
|
||||
.modal-header
|
||||
button.close(
|
||||
type="button"
|
||||
data-dismiss="modal"
|
||||
ng-click="cancel()"
|
||||
aria-label="Close"
|
||||
)
|
||||
span(aria-hidden="true") ×
|
||||
h3 #{translate("share_project")}
|
||||
.modal-body.modal-body-share
|
||||
.container-fluid
|
||||
|
||||
if isRestrictedTokenMember
|
||||
//- Token-based access
|
||||
.row.public-access-level
|
||||
.col-xs-12.access-token-display-area
|
||||
div.access-token-wrapper
|
||||
strong #{translate('anyone_with_link_can_view')}
|
||||
pre.access-token {{ readOnlyTokenLink }}
|
||||
|
||||
if !isRestrictedTokenMember
|
||||
//- Private (with token-access available)
|
||||
.row.public-access-level(ng-show="isAdmin && project.publicAccesLevel == 'private'")
|
||||
.col-xs-12.text-center
|
||||
| #{translate('link_sharing_is_off')}
|
||||
|
|
||||
a(
|
||||
href
|
||||
ng-click="makeTokenBased()"
|
||||
) #{translate('turn_on_link_sharing')}
|
||||
span
|
||||
a(
|
||||
href="/learn/how-to/What_is_Link_Sharing%3F"
|
||||
target="_blank"
|
||||
)
|
||||
i.fa.fa-question-circle(
|
||||
tooltip=translate('learn_more_about_link_sharing')
|
||||
)
|
||||
|
||||
//- Token-based access
|
||||
.row.public-access-level(ng-show="isAdmin && project.publicAccesLevel == 'tokenBased'")
|
||||
.col-xs-12.text-center
|
||||
strong
|
||||
| #{translate('link_sharing_is_on')}.
|
||||
|
|
||||
a(
|
||||
href
|
||||
ng-click="makePrivate()"
|
||||
) #{translate('turn_off_link_sharing')}
|
||||
span
|
||||
a(
|
||||
href="/learn/how-to/What_is_Link_Sharing%3F"
|
||||
target="_blank"
|
||||
)
|
||||
i.fa.fa-question-circle(
|
||||
tooltip=translate('learn_more_about_link_sharing')
|
||||
)
|
||||
|
||||
.col-xs-12.access-token-display-area
|
||||
div.access-token-wrapper
|
||||
strong #{translate('anyone_with_link_can_edit')}
|
||||
pre.access-token(ng-show="readAndWriteTokenLink") {{ readAndWriteTokenLink }}
|
||||
pre.access-token(ng-hide="readAndWriteTokenLink") #{translate('loading')}…
|
||||
div.access-token-wrapper
|
||||
strong #{translate('anyone_with_link_can_view')}
|
||||
pre.access-token(ng-show="readOnlyTokenLink") {{ readOnlyTokenLink }}
|
||||
pre.access-token(ng-hide="readOnlyTokenLink") #{translate('loading')}…
|
||||
|
||||
//- legacy public-access
|
||||
.row.public-access-level(ng-show="isAdmin && (project.publicAccesLevel == 'readAndWrite' || project.publicAccesLevel == 'readOnly')")
|
||||
.col-xs-12.text-center
|
||||
strong(ng-if="project.publicAccesLevel == 'readAndWrite'") #{translate("this_project_is_public")}
|
||||
strong(ng-if="project.publicAccesLevel == 'readOnly'") #{translate("this_project_is_public_read_only")}
|
||||
|
|
||||
a(
|
||||
href
|
||||
ng-click="makePrivate()"
|
||||
) #{translate("make_private")}
|
||||
|
||||
.row.project-member
|
||||
.col-xs-7 {{ project.owner.email }}
|
||||
.text-left.col-xs-3 #{translate("owner")}
|
||||
form.form-horizontal(
|
||||
ng-if="isAdmin"
|
||||
ng-repeat="member in project.members"
|
||||
ng-controller="ShareProjectModalMemberRowController"
|
||||
)
|
||||
.row.form-group.project-member
|
||||
.col-xs-7.form-control-static {{ member.email }}
|
||||
.col-xs-3
|
||||
select.privileges.form-control.input-sm(name="privileges" ng-model="form.privileges")
|
||||
option(value="owner") #{translate("owner")}
|
||||
option(value="readAndWrite") #{translate("can_edit")}
|
||||
option(value="readOnly") #{translate("read_only")}
|
||||
.col-xs-2.form-control-static.text-center(ng-hide="form.isModified()")
|
||||
a(
|
||||
href
|
||||
tooltip=translate('remove_collaborator')
|
||||
tooltip-placement="bottom"
|
||||
ng-click="removeMember(member)"
|
||||
aria-label=translate('remove_collaborator')
|
||||
)
|
||||
i.fa.fa-times
|
||||
.col-xs-2.text-center(ng-show="form.isModified()")
|
||||
button.btn.btn-sm.btn-success(
|
||||
type="submit"
|
||||
ng-click="form.submit()"
|
||||
) #{translate("change")}
|
||||
.text-sm
|
||||
| #{translate("or")}
|
||||
|
|
||||
button.btn.btn-inline-link(ng-click="form.reset()") #{translate("cancel").toLowerCase()}
|
||||
|
||||
.row.project-member(ng-if="!isAdmin" ng-repeat="member in project.members")
|
||||
.col-xs-7 {{ member.email }}
|
||||
.col-xs-3
|
||||
span(ng-if="member.privileges == 'readAndWrite'") #{translate("can_edit")}
|
||||
span(ng-if="member.privileges == 'readOnly'") #{translate("read_only")}
|
||||
.row.project-invite(ng-repeat="invite in project.invites")
|
||||
.col-xs-7 {{ invite.email }}
|
||||
div.small
|
||||
| #{translate("invite_not_accepted")}.
|
||||
button.btn.btn-inline-link(
|
||||
ng-show="isAdmin",
|
||||
ng-click="resendInvite(invite, $event)"
|
||||
) #{translate("resend")}
|
||||
.col-xs-3.text-left
|
||||
// todo: get invite privileges
|
||||
span(ng-show="invite.privileges == 'readAndWrite'") #{translate("can_edit")}
|
||||
span(ng-show="invite.privileges == 'readOnly'") #{translate("read_only")}
|
||||
.col-xs-2.text-center(ng-if="isAdmin")
|
||||
a(
|
||||
href
|
||||
tooltip=translate('revoke_invite')
|
||||
tooltip-placement="bottom"
|
||||
ng-click="revokeInvite(invite)"
|
||||
)
|
||||
i.fa.fa-times
|
||||
.row.invite-controls(ng-show="isAdmin")
|
||||
form(ng-show="canAddCollaborators")
|
||||
.small #{translate("share_with_your_collabs")}
|
||||
.form-group
|
||||
tags-input(
|
||||
class="tags-input"
|
||||
template="shareTagTemplate"
|
||||
placeholder=settings.customisation.shareProjectPlaceholder || 'joe@example.com, sue@example.com, …'
|
||||
ng-model="inputs.contacts"
|
||||
focus-on="open"
|
||||
display-property="display"
|
||||
add-on-paste="true"
|
||||
add-on-enter="false"
|
||||
replace-spaces-with-dashes="false"
|
||||
type="email"
|
||||
)
|
||||
auto-complete(
|
||||
source="filterAutocompleteUsers($query)"
|
||||
template="shareAutocompleteTemplate"
|
||||
display-property="email"
|
||||
min-length="0"
|
||||
)
|
||||
.form-group
|
||||
.pull-right
|
||||
select.privileges.form-control(
|
||||
ng-model="inputs.privileges"
|
||||
name="privileges"
|
||||
)
|
||||
option(value="readAndWrite") #{translate("can_edit")}
|
||||
option(value="readOnly") #{translate("read_only")}
|
||||
|
|
||||
//- We have to use mousedown here since click has issues with the
|
||||
//- blur handler in tags-input sometimes changing its height and
|
||||
//- moving this button, preventing the click registering.
|
||||
button.btn.btn-info(
|
||||
type="submit"
|
||||
ng-mousedown="addMembers()"
|
||||
ng-keyup="$event.keyCode == 13 ? addMembers() : null"
|
||||
) #{translate("share")}
|
||||
div(ng-hide="canAddCollaborators")
|
||||
p.text-center #{translate("need_to_upgrade_for_more_collabs")}. Also:
|
||||
.row
|
||||
.col-md-8.col-md-offset-2
|
||||
ul.list-unstyled
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("unlimited_projects")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("collabs_per_proj", {collabcount:'Multiple'})}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("full_doc_history")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("sync_to_dropbox")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("sync_to_github")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
|#{translate("compile_larger_projects")}
|
||||
p.text-center.row-spaced-thin(ng-show="user.allowedFreeTrial" ng-controller="FreeTrialModalController")
|
||||
a.btn.btn-success(
|
||||
href
|
||||
ng-class="buttonClass"
|
||||
ng-click="startFreeTrial('projectMembers')"
|
||||
) #{translate("start_free_trial")}
|
||||
|
||||
p.text-center.row-spaced-thin(ng-show="!user.allowedFreeTrial" ng-controller="UpgradeModalController")
|
||||
a.btn.btn-success(
|
||||
href
|
||||
ng-class="buttonClass"
|
||||
ng-click="upgradePlan('projectMembers')"
|
||||
) #{translate("upgrade")}
|
||||
|
||||
p.small(ng-show="startedFreeTrial")
|
||||
| #{translate("refresh_page_after_starting_free_trial")}
|
||||
.row.public-access-level.public-access-level--notice(ng-show="!isAdmin")
|
||||
.col-xs-12.text-center(ng-show="project.publicAccesLevel == 'private'") #{translate("to_add_more_collaborators")}
|
||||
.col-xs-12.text-center(ng-show="project.publicAccesLevel == 'tokenBased'") #{translate("to_change_access_permissions")}
|
||||
.modal-footer.modal-footer-share
|
||||
.modal-footer-left
|
||||
i.fa.fa-refresh.fa-spin(ng-show="state.inflight")
|
||||
span.text-danger.error(ng-show="state.error")
|
||||
span(ng-switch="state.errorReason")
|
||||
span(ng-switch-when="cannot_invite_non_user")
|
||||
| #{translate("cannot_invite_non_user")}
|
||||
span(ng-switch-when="cannot_verify_user_not_robot")
|
||||
| #{translate("cannot_verify_user_not_robot")}
|
||||
span(ng-switch-when="cannot_invite_self")
|
||||
| #{translate("cannot_invite_self")}
|
||||
span(ng-switch-when="invalid_email")
|
||||
| #{translate("invalid_email")}
|
||||
span(ng-switch-default)
|
||||
| #{translate("generic_something_went_wrong")}
|
||||
.modal-footer-right
|
||||
button.btn.btn-default(
|
||||
ng-click="done()"
|
||||
) #{translate("close")}
|
||||
|
||||
script(type="text/ng-template", id="shareTagTemplate")
|
||||
.tag-template
|
||||
span(ng-if="data.type")
|
||||
i.fa.fa-fw(ng-class="{'fa-user': data.type != 'group', 'fa-group': data.type == 'group'}")
|
||||
|
|
||||
span {{$getDisplayText()}}
|
||||
|
|
||||
a(href, ng-click="$removeTag()").remove-button
|
||||
i.fa.fa-fw.fa-close
|
||||
|
||||
script(type="text/ng-template", id="shareAutocompleteTemplate")
|
||||
.autocomplete-template
|
||||
div(ng-if="data.type == 'user'")
|
||||
i.fa.fa-fw.fa-user
|
||||
|
|
||||
span(ng-bind-html="$highlight(data.display)")
|
||||
div(ng-if="data.type == 'group'")
|
||||
i.fa.fa-fw.fa-group
|
||||
|
|
||||
span(ng-bind-html="$highlight(data.name)")
|
||||
span.subdued.small(ng-show="data.member_count") ({{ data.member_count }} members)
|
||||
|
||||
script(type="text/ng-template", id="ownershipTransferConfirmTemplate")
|
||||
.modal-header
|
||||
button.close(
|
||||
type="button"
|
||||
data-dismiss="modal"
|
||||
ng-click="cancel()"
|
||||
aria-label="Close"
|
||||
)
|
||||
span(aria-hidden="true") ×
|
||||
h3 #{translate("change_project_owner")}
|
||||
.modal-body
|
||||
p !{translate('project_ownership_transfer_confirmation_1', { user: '{{ member.email }}', project: '{{ project.name }}' }, ['strong', 'strong'])}
|
||||
p #{translate('project_ownership_transfer_confirmation_2')}
|
||||
.modal-footer
|
||||
.modal-footer-left
|
||||
i.fa.fa-refresh.fa-spin(ng-show="state.inflight")
|
||||
span.text-danger.error(ng-show="state.error") #{translate("generic_something_went_wrong")}
|
||||
.modal-footer-right
|
||||
button.btn.btn-default(ng-click="cancel()") #{translate("cancel")}
|
||||
button.btn.btn-success(ng-click="confirm()") #{translate("change_owner")}
|
|
@ -35,7 +35,6 @@ const App = angular
|
|||
'ErrorCatcher',
|
||||
'localStorage',
|
||||
'sessionStorage',
|
||||
'ngTagsInput',
|
||||
'ui.select',
|
||||
])
|
||||
.config(function ($qProvider, $httpProvider, uiSelectConfig) {
|
||||
|
|
|
@ -35,7 +35,6 @@ import SafariScrollPatcher from './ide/SafariScrollPatcher'
|
|||
import { loadServiceWorker } from './ide/pdfng/directives/serviceWorkerManager'
|
||||
import './ide/cobranding/CobrandingDataService'
|
||||
import './ide/settings/index'
|
||||
import './ide/share/index'
|
||||
import './ide/binary-files/index'
|
||||
import './ide/chat/index'
|
||||
import './ide/clone/index'
|
||||
|
@ -64,6 +63,7 @@ import './main/system-messages'
|
|||
import '../../modules/modules-ide.js'
|
||||
import './shared/context/controllers/root-context-controller'
|
||||
import './features/editor-navigation-toolbar/controllers/editor-navigation-toolbar-controller'
|
||||
import './features/share-project-modal/controllers/react-share-project-modal-controller'
|
||||
import getMeta from './utils/meta'
|
||||
|
||||
App.controller(
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import App from '../../../base'
|
||||
App.controller(
|
||||
'OwnershipTransferConfirmModalController',
|
||||
function ($scope, $window, $modalInstance, projectMembers) {
|
||||
$scope.state = {
|
||||
inflight: false,
|
||||
error: false,
|
||||
}
|
||||
|
||||
$scope.confirm = function () {
|
||||
const userId = $scope.member._id
|
||||
transferOwnership(userId)
|
||||
}
|
||||
|
||||
$scope.cancel = function () {
|
||||
$modalInstance.dismiss()
|
||||
}
|
||||
|
||||
function transferOwnership(userId) {
|
||||
$scope.state.inflight = true
|
||||
$scope.state.error = false
|
||||
projectMembers
|
||||
.transferOwnership(userId)
|
||||
.then(() => {
|
||||
$scope.state.inflight = false
|
||||
$scope.state.error = false
|
||||
$window.location.reload()
|
||||
})
|
||||
.catch(() => {
|
||||
$scope.state.inflight = false
|
||||
$scope.state.error = true
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
|
@ -1,55 +0,0 @@
|
|||
import App from '../../../base'
|
||||
App.controller('ShareController', function (
|
||||
$scope,
|
||||
$modal,
|
||||
ide,
|
||||
projectInvites,
|
||||
projectMembers,
|
||||
// eslint-disable-next-line camelcase
|
||||
eventTracking
|
||||
) {
|
||||
$scope.openShareProjectModal = function (isAdmin) {
|
||||
$scope.isAdmin = isAdmin
|
||||
eventTracking.sendMBOnce('ide-open-share-modal-once')
|
||||
|
||||
$modal.open({
|
||||
templateUrl: 'shareProjectModalTemplate',
|
||||
controller: 'ShareProjectModalController',
|
||||
scope: $scope,
|
||||
})
|
||||
}
|
||||
|
||||
ide.socket.on('project:tokens:changed', data => {
|
||||
if (data.tokens != null) {
|
||||
ide.$scope.project.tokens = data.tokens
|
||||
$scope.$digest()
|
||||
}
|
||||
})
|
||||
|
||||
ide.socket.on('project:membership:changed', data => {
|
||||
if (data.members) {
|
||||
projectMembers
|
||||
.getMembers()
|
||||
.then(response => {
|
||||
if (response.data.members) {
|
||||
$scope.project.members = response.data.members
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Error fetching members for project')
|
||||
})
|
||||
}
|
||||
if (data.invites) {
|
||||
projectInvites
|
||||
.getInvites()
|
||||
.then(response => {
|
||||
if (response.data.invites) {
|
||||
$scope.project.invites = response.data.invites
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Error fetching invites for project')
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
|
@ -1,309 +0,0 @@
|
|||
import _ from 'lodash'
|
||||
import App from '../../../base'
|
||||
App.controller('ShareProjectModalController', function (
|
||||
$scope,
|
||||
$modalInstance,
|
||||
$timeout,
|
||||
projectMembers,
|
||||
projectInvites,
|
||||
$modal,
|
||||
$http,
|
||||
ide,
|
||||
validateCaptcha,
|
||||
validateCaptchaV3,
|
||||
settings,
|
||||
// eslint-disable-next-line camelcase
|
||||
eventTracking
|
||||
) {
|
||||
$scope.inputs = {
|
||||
privileges: 'readAndWrite',
|
||||
contacts: [],
|
||||
}
|
||||
$scope.state = {
|
||||
error: null,
|
||||
errorReason: null,
|
||||
inflight: false,
|
||||
startedFreeTrial: false,
|
||||
invites: [],
|
||||
}
|
||||
|
||||
$modalInstance.opened.then(() =>
|
||||
$timeout(() => $scope.$broadcast('open'), 200)
|
||||
)
|
||||
|
||||
const INFINITE_COLLABORATORS = -1
|
||||
|
||||
$scope.refreshCanAddCollaborators = function () {
|
||||
const allowedNoOfMembers = $scope.project.features.collaborators
|
||||
$scope.canAddCollaborators =
|
||||
$scope.project.members.length + $scope.project.invites.length <
|
||||
allowedNoOfMembers || allowedNoOfMembers === INFINITE_COLLABORATORS
|
||||
}
|
||||
$scope.refreshCanAddCollaborators()
|
||||
|
||||
$scope.$watch('canAddCollaborators', function () {
|
||||
if (!$scope.canAddCollaborators) {
|
||||
eventTracking.send(
|
||||
'subscription-funnel',
|
||||
'editor-click-feature',
|
||||
'projectMembers'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
$scope.$watch(
|
||||
'(project.members.length + project.invites.length)',
|
||||
_noOfMembers => $scope.refreshCanAddCollaborators()
|
||||
)
|
||||
|
||||
$scope.autocompleteContacts = []
|
||||
if ($scope.isRestrictedTokenMember) {
|
||||
// Restricted token members are users who join via a read-only link.
|
||||
// They will not be able to invite any users, so skip the lookup of
|
||||
// their contacts. This request would result in a 403 for anonymous
|
||||
// users, which in turn would redirect them to the /login.
|
||||
} else {
|
||||
$http.get('/user/contacts').then(processContactsResponse)
|
||||
}
|
||||
|
||||
function processContactsResponse(response) {
|
||||
const { data } = response
|
||||
$scope.autocompleteContacts = data.contacts || []
|
||||
for (const contact of $scope.autocompleteContacts) {
|
||||
if (contact.type === 'user') {
|
||||
if (
|
||||
contact.first_name === contact.email.split('@')[0] &&
|
||||
!contact.last_name
|
||||
) {
|
||||
// User has not set their proper name so use email as canonical display property
|
||||
contact.display = contact.email
|
||||
} else {
|
||||
contact.name = `${contact.first_name} ${contact.last_name}`
|
||||
contact.display = `${contact.name} <${contact.email}>`
|
||||
}
|
||||
} else {
|
||||
// Must be a group
|
||||
contact.display = contact.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getCurrentMemberEmails = () =>
|
||||
($scope.project.members || []).map(u => u.email)
|
||||
|
||||
const getCurrentInviteEmails = () =>
|
||||
($scope.project.invites || []).map(u => u.email)
|
||||
|
||||
$scope.filterAutocompleteUsers = function ($query) {
|
||||
const currentMemberEmails = getCurrentMemberEmails()
|
||||
return $scope.autocompleteContacts.filter(function (contact) {
|
||||
if (
|
||||
contact.email != null &&
|
||||
currentMemberEmails.includes(contact.email)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
for (const text of [contact.name, contact.email]) {
|
||||
if (
|
||||
text != null &&
|
||||
text.toLowerCase().indexOf($query.toLowerCase()) > -1
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
$scope.addMembers = function () {
|
||||
const addMembers = function () {
|
||||
if ($scope.inputs.contacts.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const members = $scope.inputs.contacts
|
||||
$scope.inputs.contacts = []
|
||||
$scope.clearError()
|
||||
$scope.state.inflight = true
|
||||
|
||||
if ($scope.project.invites == null) {
|
||||
$scope.project.invites = []
|
||||
}
|
||||
|
||||
const currentMemberEmails = getCurrentMemberEmails()
|
||||
const currentInviteEmails = getCurrentInviteEmails()
|
||||
addNextMember()
|
||||
|
||||
function addNextMember() {
|
||||
let email
|
||||
if (members.length === 0 || !$scope.canAddCollaborators) {
|
||||
$scope.state.inflight = false
|
||||
$scope.$apply()
|
||||
return
|
||||
}
|
||||
|
||||
const member = members.shift()
|
||||
if (member.type === 'user') {
|
||||
email = member.email
|
||||
} else {
|
||||
// Not an auto-complete object, so email == display
|
||||
email = member.display
|
||||
}
|
||||
email = email.toLowerCase()
|
||||
|
||||
if (currentMemberEmails.includes(email)) {
|
||||
// Skip this existing member
|
||||
return addNextMember()
|
||||
}
|
||||
// do v3 captcha to collect data only
|
||||
validateCaptchaV3('invite')
|
||||
// do v2 captcha
|
||||
const ExposedSettings = window.ExposedSettings
|
||||
validateCaptcha(function (response) {
|
||||
$scope.grecaptchaResponse = response
|
||||
const invites = $scope.project.invites || []
|
||||
const invite = _.find(invites, invite => invite.email === email)
|
||||
let request
|
||||
if (currentInviteEmails.includes(email) && invite) {
|
||||
request = projectInvites.resendInvite(invite._id)
|
||||
} else {
|
||||
request = projectInvites.sendInvite(
|
||||
email,
|
||||
$scope.inputs.privileges,
|
||||
$scope.grecaptchaResponse
|
||||
)
|
||||
}
|
||||
|
||||
request
|
||||
.then(function (response) {
|
||||
const { data } = response
|
||||
if (data.error) {
|
||||
$scope.setError(data.error)
|
||||
$scope.state.inflight = false
|
||||
} else {
|
||||
if (data.invite) {
|
||||
const { invite } = data
|
||||
$scope.project.invites.push(invite)
|
||||
} else {
|
||||
const users =
|
||||
data.users != null
|
||||
? data.users
|
||||
: data.user != null
|
||||
? [data.user]
|
||||
: []
|
||||
$scope.project.members.push(...users)
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(
|
||||
() =>
|
||||
// Give $scope a chance to update $scope.canAddCollaborators
|
||||
// with new collaborator information.
|
||||
addNextMember(),
|
||||
|
||||
0
|
||||
)
|
||||
})
|
||||
.catch(function (httpResponse) {
|
||||
const { data } = httpResponse
|
||||
$scope.state.inflight = false
|
||||
$scope.setError(data.errorReason)
|
||||
})
|
||||
}, ExposedSettings.recaptchaDisabled.invite)
|
||||
}
|
||||
}
|
||||
|
||||
$timeout(addMembers, 50) // Give email list a chance to update
|
||||
}
|
||||
|
||||
$scope.removeMember = function (member) {
|
||||
$scope.monitorRequest(
|
||||
projectMembers.removeMember(member).then(function () {
|
||||
const index = $scope.project.members.indexOf(member)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
$scope.project.members.splice(index, 1)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
$scope.revokeInvite = function (invite) {
|
||||
$scope.monitorRequest(
|
||||
projectInvites.revokeInvite(invite._id).then(function () {
|
||||
const index = $scope.project.invites.indexOf(invite)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
$scope.project.invites.splice(index, 1)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
$scope.resendInvite = function (invite, event) {
|
||||
$scope.monitorRequest(
|
||||
projectInvites
|
||||
.resendInvite(invite._id)
|
||||
.then(function () {
|
||||
event.target.blur()
|
||||
})
|
||||
.catch(function () {
|
||||
event.target.blur()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
$scope.makeTokenBased = function () {
|
||||
$scope.project.publicAccesLevel = 'tokenBased'
|
||||
settings.saveProjectAdminSettings({ publicAccessLevel: 'tokenBased' })
|
||||
eventTracking.sendMB('project-make-token-based')
|
||||
}
|
||||
|
||||
$scope.makePrivate = function () {
|
||||
$scope.project.publicAccesLevel = 'private'
|
||||
settings.saveProjectAdminSettings({ publicAccessLevel: 'private' })
|
||||
}
|
||||
|
||||
$scope.$watch('project.tokens.readAndWrite', function (token) {
|
||||
if (token != null) {
|
||||
$scope.readAndWriteTokenLink = `${location.origin}/${token}`
|
||||
} else {
|
||||
$scope.readAndWriteTokenLink = null
|
||||
}
|
||||
})
|
||||
|
||||
$scope.$watch('project.tokens.readOnly', function (token) {
|
||||
if (token != null) {
|
||||
$scope.readOnlyTokenLink = `${location.origin}/read/${token}`
|
||||
} else {
|
||||
$scope.readOnlyTokenLink = null
|
||||
}
|
||||
})
|
||||
|
||||
$scope.done = () => $modalInstance.close()
|
||||
|
||||
$scope.cancel = () => $modalInstance.dismiss()
|
||||
|
||||
$scope.monitorRequest = function monitorRequest(request) {
|
||||
$scope.clearError()
|
||||
$scope.state.inflight = true
|
||||
return request
|
||||
.then(() => {
|
||||
$scope.state.inflight = false
|
||||
$scope.clearError()
|
||||
})
|
||||
.catch(err => {
|
||||
$scope.state.inflight = false
|
||||
$scope.setError(err.data && err.data.error)
|
||||
})
|
||||
}
|
||||
|
||||
$scope.clearError = function clearError() {
|
||||
$scope.state.error = false
|
||||
}
|
||||
|
||||
$scope.setError = function setError(reason) {
|
||||
$scope.state.error = true
|
||||
$scope.state.errorReason = reason
|
||||
}
|
||||
})
|
|
@ -1,46 +0,0 @@
|
|||
import App from '../../../base'
|
||||
App.controller(
|
||||
'ShareProjectModalMemberRowController',
|
||||
function ($scope, $modal, projectMembers) {
|
||||
$scope.form = {
|
||||
privileges: $scope.member.privileges,
|
||||
|
||||
isModified() {
|
||||
return this.privileges !== $scope.member.privileges
|
||||
},
|
||||
|
||||
submit() {
|
||||
const userId = $scope.member._id
|
||||
const privilegeLevel = $scope.form.privileges
|
||||
if (privilegeLevel === 'owner') {
|
||||
openOwnershipTransferConfirmModal(userId)
|
||||
} else {
|
||||
setPrivilegeLevel(userId, privilegeLevel)
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.privileges = $scope.member.privileges
|
||||
$scope.clearError()
|
||||
},
|
||||
}
|
||||
|
||||
function setPrivilegeLevel(userId, privilegeLevel) {
|
||||
$scope.monitorRequest(
|
||||
projectMembers
|
||||
.setMemberPrivilegeLevel(userId, privilegeLevel)
|
||||
.then(() => {
|
||||
$scope.member.privileges = privilegeLevel
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function openOwnershipTransferConfirmModal(userId) {
|
||||
$modal.open({
|
||||
templateUrl: 'ownershipTransferConfirmTemplate',
|
||||
controller: 'OwnershipTransferConfirmModalController',
|
||||
scope: $scope,
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
|
@ -1,7 +0,0 @@
|
|||
import './controllers/ShareController'
|
||||
import './controllers/ShareProjectModalController'
|
||||
import './controllers/ShareProjectModalMemberRowController'
|
||||
import './controllers/OwnershipTransferConfirmModalController'
|
||||
import './services/projectMembers'
|
||||
import './services/projectInvites'
|
||||
import '../../features/share-project-modal/controllers/react-share-project-modal-controller'
|
|
@ -1,37 +0,0 @@
|
|||
import App from '../../../base'
|
||||
|
||||
export default App.factory('projectInvites', (ide, $http) => ({
|
||||
sendInvite(email, privileges, grecaptchaResponse) {
|
||||
return $http.post(`/project/${ide.project_id}/invite`, {
|
||||
email,
|
||||
privileges,
|
||||
_csrf: window.csrfToken,
|
||||
'g-recaptcha-response': grecaptchaResponse,
|
||||
})
|
||||
},
|
||||
|
||||
revokeInvite(inviteId) {
|
||||
return $http({
|
||||
url: `/project/${ide.project_id}/invite/${inviteId}`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-Csrf-Token': window.csrfToken,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
resendInvite(inviteId, privileges) {
|
||||
return $http.post(`/project/${ide.project_id}/invite/${inviteId}/resend`, {
|
||||
_csrf: window.csrfToken,
|
||||
})
|
||||
},
|
||||
|
||||
getInvites() {
|
||||
return $http.get(`/project/${ide.project_id}/invites`, {
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Csrf-Token': window.csrfToken,
|
||||
},
|
||||
})
|
||||
},
|
||||
}))
|
|
@ -1,48 +0,0 @@
|
|||
import App from '../../../base'
|
||||
App.factory('projectMembers', (ide, $http) => ({
|
||||
removeMember(member) {
|
||||
return $http({
|
||||
url: `/project/${ide.project_id}/users/${member._id}`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-Csrf-Token': window.csrfToken,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
addGroup(groupId, privileges) {
|
||||
return $http.post(`/project/${ide.project_id}/group`, {
|
||||
group_id: groupId,
|
||||
privileges,
|
||||
_csrf: window.csrfToken,
|
||||
})
|
||||
},
|
||||
|
||||
getMembers() {
|
||||
return $http.get(`/project/${ide.project_id}/members`, {
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Csrf-Token': window.csrfToken,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
setMemberPrivilegeLevel(userId, privilegeLevel) {
|
||||
return $http.put(
|
||||
`/project/${ide.project_id}/users/${userId}`,
|
||||
{ privilegeLevel },
|
||||
{
|
||||
headers: {
|
||||
'X-Csrf-Token': window.csrfToken,
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
transferOwnership(userId) {
|
||||
return $http.post(`/project/${ide.project_id}/transfer-ownership`, {
|
||||
user_id: userId,
|
||||
_csrf: window.csrfToken,
|
||||
})
|
||||
},
|
||||
}))
|
|
@ -8,7 +8,6 @@ import 'libs/ng-context-menu-0.1.4'
|
|||
import 'libs/jquery.storage'
|
||||
import 'libs/angular-cookie'
|
||||
import 'libs/passfield'
|
||||
import 'libs/ng-tags-input-3.0.0'
|
||||
import 'libs/select/select'
|
||||
|
||||
// CSS
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue