-
checked="checked"<% } %>/>
+
disabled="disabled"<% } %> <% if(permission.active) { %>checked="checked"<% } %>/>
Yes
No
@@ -279,10 +299,23 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) ->
setActivePermissions = (permissions) ->
return _.map(permissions, (x) -> _.extend({}, x, {active: x["key"] in role.permissions}))
+ isPermissionEditable = (permission, role, project) ->
+ if role.external_user &&
+ !project.is_private &&
+ permission.key.indexOf("view_") == 0
+ return false
+ else
+ return true
+
setActivePermissionsPerCategory = (category) ->
- return _.map(category, (x) ->
- _.extend({}, x, {
- activePermissions: _.filter(x["permissions"], "active").length
+ return _.map(category, (cat) ->
+ cat.permissions = cat.permissions.map (permission) ->
+ permission.editable = isPermissionEditable(permission, role, $scope.project)
+
+ return permission
+
+ _.extend({}, cat, {
+ activePermissions: _.filter(cat["permissions"], "active").length
})
)
@@ -366,10 +399,11 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) ->
return activePermissions
target = angular.element(event.currentTarget)
+
$scope.role.permissions = getActivePermissions()
- onSuccess = (role) ->
- categories = generateCategoriesFromRole(role)
+ onSuccess = () ->
+ categories = generateCategoriesFromRole($scope.role)
categoryId = target.parents(".category-config").data("id")
renderResume(target.parents(".category-config"), categories[categoryId])
$rootscope.$broadcast("projects:reload")
@@ -381,7 +415,14 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) ->
target.prop "checked", !target.prop("checked")
$scope.role.permissions = getActivePermissions()
- $repo.save($scope.role).then onSuccess, onError
+ if $scope.role.external_user
+ $scope.project.public_permissions = $scope.role.permissions
+ $scope.project.anon_permissions = $scope.role.permissions.filter (permission) ->
+ return permission.indexOf("view_") == 0
+
+ $repo.save($scope.project).then onSuccess, onError
+ else
+ $repo.save($scope.role).then onSuccess, onError
$scope.$on "$destroy", ->
$el.off()
diff --git a/app/coffee/modules/common/history.coffee b/app/coffee/modules/common/history.coffee
index fcd1d961..c7ab11d5 100644
--- a/app/coffee/modules/common/history.coffee
+++ b/app/coffee/modules/common/history.coffee
@@ -258,7 +258,7 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) ->
deleteCommentDate: moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm") if comment.delete_comment_date
deleteCommentUser: comment.delete_comment_user.name if comment.delete_comment_user?.name
activityId: comment.id
- canDeleteComment: comment.user.pk == $scope.user.id or $scope.project.my_permissions.indexOf("modify_project") > -1
+ canDeleteComment: comment.user.pk == $scope.user?.id or $scope.project.my_permissions.indexOf("modify_project") > -1
})
renderChange = (change) ->
diff --git a/app/coffee/modules/taskboard/sortable.coffee b/app/coffee/modules/taskboard/sortable.coffee
index 16aa5020..57f99711 100644
--- a/app/coffee/modules/taskboard/sortable.coffee
+++ b/app/coffee/modules/taskboard/sortable.coffee
@@ -36,47 +36,52 @@ module = angular.module("taigaBacklog")
TaskboardSortableDirective = ($repo, $rs, $rootscope) ->
link = ($scope, $el, $attrs) ->
- oldParentScope = null
- newParentScope = null
- itemEl = null
- tdom = $el
+ bindOnce $scope, "project", (project) ->
+ # If the user has not enough permissions we don't enable the sortable
+ if not (project.my_permissions.indexOf("modify_us") > -1)
+ return
- deleteElement = (itemEl) ->
- # Completelly remove item and its scope from dom
- itemEl.scope().$destroy()
- itemEl.off()
- itemEl.remove()
+ oldParentScope = null
+ newParentScope = null
+ itemEl = null
+ tdom = $el
- tdom.sortable({
- handle: ".taskboard-task-inner",
- dropOnEmpty: true
- connectWith: ".taskboard-tasks-box"
- revert: 400
- })
+ deleteElement = (itemEl) ->
+ # Completelly remove item and its scope from dom
+ itemEl.scope().$destroy()
+ itemEl.off()
+ itemEl.remove()
- tdom.on "sortstop", (event, ui) ->
- parentEl = ui.item.parent()
- itemEl = ui.item
- itemTask = itemEl.scope().task
- itemIndex = itemEl.index()
- newParentScope = parentEl.scope()
+ tdom.sortable({
+ handle: ".taskboard-task-inner",
+ dropOnEmpty: true
+ connectWith: ".taskboard-tasks-box"
+ revert: 400
+ })
- oldUsId = if oldParentScope.us then oldParentScope.us.id else null
- oldStatusId = oldParentScope.st.id
- newUsId = if newParentScope.us then newParentScope.us.id else null
- newStatusId = newParentScope.st.id
+ tdom.on "sortstop", (event, ui) ->
+ parentEl = ui.item.parent()
+ itemEl = ui.item
+ itemTask = itemEl.scope().task
+ itemIndex = itemEl.index()
+ newParentScope = parentEl.scope()
- if newStatusId != oldStatusId or newUsId != oldUsId
- deleteElement(itemEl)
+ oldUsId = if oldParentScope.us then oldParentScope.us.id else null
+ oldStatusId = oldParentScope.st.id
+ newUsId = if newParentScope.us then newParentScope.us.id else null
+ newStatusId = newParentScope.st.id
- $scope.$apply ->
- $rootscope.$broadcast("taskboard:task:move", itemTask, newUsId, newStatusId, itemIndex)
+ if newStatusId != oldStatusId or newUsId != oldUsId
+ deleteElement(itemEl)
- ui.item.find('a').removeClass('noclick')
+ $scope.$apply ->
+ $rootscope.$broadcast("taskboard:task:move", itemTask, newUsId, newStatusId, itemIndex)
- tdom.on "sortstart", (event, ui) ->
- oldParentScope = ui.item.parent().scope()
- ui.item.find('a').addClass('noclick')
+ ui.item.find('a').removeClass('noclick')
+
+ tdom.on "sortstart", (event, ui) ->
+ oldParentScope = ui.item.parent().scope()
+ ui.item.find('a').addClass('noclick')
$scope.$on "$destroy", ->
$el.off()
diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee
index 69830a2f..9bc9b57a 100644
--- a/app/coffee/modules/team/main.coffee
+++ b/app/coffee/modules/team/main.coffee
@@ -69,18 +69,18 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin)
loadMembers: ->
return @rs.memberships.list(@scope.projectId, {}, false).then (data) =>
currentUser = @auth.getUser()
- if not currentUser.photo?
+ if currentUser? and not currentUser.photo?
currentUser.photo = "/images/unnamed.png"
@scope.currentUser = _.find data, (membership) =>
- return membership.user == currentUser.id
+ return currentUser? and membership.user == currentUser.id
@scope.totals = {}
_.forEach data, (membership) =>
@scope.totals[membership.user] = 0
@scope.memberships = _.filter data, (membership) =>
- if membership.user && membership.user != currentUser.id && membership.is_user_active
+ if membership.user && (not currentUser? or membership.user != currentUser.id) && membership.is_user_active
return membership
for membership in @scope.memberships
diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee
index 381c4848..8aad38e7 100644
--- a/app/coffee/modules/wiki/main.coffee
+++ b/app/coffee/modules/wiki/main.coffee
@@ -238,6 +238,7 @@ EditableWikiContentDirective = ($window, $document, $repo, $confirm, $loading, $
$el.on "mouseup", ".view-wiki-content", (event) ->
target = angular.element(event.target)
return if getSelectedText()
+ return if not isEditable()
return if target.is('a')
return if target.is('pre')
diff --git a/app/partials/admin/admin-project-profile.jade b/app/partials/admin/admin-project-profile.jade
index 6ee7c272..b504ceb9 100644
--- a/app/partials/admin/admin-project-profile.jade
+++ b/app/partials/admin/admin-project-profile.jade
@@ -40,16 +40,14 @@ div.wrapper(tg-project-profile, ng-controller="ProjectProfileController as ctrl"
tg-privacy-settings-inputs
div.privacy-settings
div
- input.hidden(type="radio", disabled="disabled")
+ input.privacy-project(type="radio", name="private-project", ng-model="project.is_private", ng-value="false")
label.trans-button(for="public-project")
span Public Project
div
- input.hidden(type="radio", checked="checked", disabled="disabled")
+ input.privacy-project(type="radio", name="private-project", ng-model="project.is_private", ng-value="true")
label.trans-button(for="private-project")
span Private Project
- p All projects are private during Taiga's beta period.
-
button.button-green.submit-button(type="submit", title="Save") Save
a.delete-project(href="", title="Delete this project", ng-click="ctrl.openDeleteLightbox()") Delete this project
diff --git a/app/partials/admin/admin-roles.jade b/app/partials/admin/admin-roles.jade
index 52dc954f..2899d960 100644
--- a/app/partials/admin/admin-roles.jade
+++ b/app/partials/admin/admin-roles.jade
@@ -8,28 +8,33 @@ div.wrapper.roles(ng-controller="RolesController as ctrl",
section.main.admin-roles.admin-common
.header-with-actions
include ../includes/components/mainTitle
- .action-buttons
+ .action-buttons(ng-if="!role.external_user")
a.button-red.delete-role(href="", title="Delete", ng-click="ctrl.delete()")
span Delete
- div(tg-edit-role)
- .edit-role
- input(type="text", value="{{ role.name }}")
- a.save.icon.icon-floppy(href="", title="Save")
+ div(ng-if="!role.external_user")
+ div(tg-edit-role)
+ .edit-role
+ input(type="text", value="{{ role.name }}")
+ a.save.icon.icon-floppy(href="", title="Save")
+ p.total
+ span.role-name(title="{{ role.members_count }} members with this role") {{ role.name }}
+ a.edit-value.icon.icon-edit
+
+ div.any-computable-role(ng-hide="anyComputableRole") Be careful, no role in your project will be able to estimate the point value for user stories
+
+ div.general-category
+ | When enabled, members assigned to this role will be able to estimate the point value for user stories
+ div.check
+ input(type="checkbox", ng-model="role.computable", ng-change="ctrl.setComputable()")
+ div
+ span.check-text.check-yes Yes
+ span.check-text.check-no No
+
+ div(ng-if="role.external_user")
p.total
- span.role-name(title="{{ role.members_count }} members with this role") {{ role.name }}
- a.edit-value.icon.icon-edit
-
- div.any-computable-role(ng-hide="anyComputableRole") Be careful, no role in your project will be able to estimate the point value for user stories
-
- div.general-category
- | When enabled, members assigned to this role will be able to estimate the point value for user stories
- div.check
- input(type="checkbox", ng-model="role.computable", ng-change="ctrl.setComputable()")
- div
- span.check-text.check-yes Yes
- span.check-text.check-no No
+ span.role-name {{ role.name }}
div(tg-role-permissions, ng-model="role")
diff --git a/app/partials/includes/modules/team/team-table.jade b/app/partials/includes/modules/team/team-table.jade
index 9ee2279c..f4e0c739 100644
--- a/app/partials/includes/modules/team/team-table.jade
+++ b/app/partials/includes/modules/team/team-table.jade
@@ -27,7 +27,7 @@ section.table-team.basic-table
div.popover.attribute-explanation
span Total Points
- div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled")
+ div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled", ng-if="::currentUser")
h2(ng-show="memberships.length")
span Team >
diff --git a/app/partials/project/project-menu.jade b/app/partials/project/project-menu.jade
index 9b70ae09..ea56ff56 100644
--- a/app/partials/project/project-menu.jade
+++ b/app/partials/project/project-menu.jade
@@ -44,6 +44,7 @@ div(class="menu-container")
span(class="icon icon-settings")
span(class="item") Admin
<% } %>
+ <% if (user) { %>
div(class="user")
div(class="user-settings")
ul(class="popover")
@@ -61,3 +62,4 @@ div(class="menu-container")
a(href="" title="Logout" class="logout") Logout
a(href="" title="User preferences" class="avatar" id="nav-user-settings")
img(src="{{ user.photo }}" alt="{{ user.full_name_display }}")
+ <% } %>
diff --git a/app/styles/layout/wiki.scss b/app/styles/layout/wiki.scss
index 9bb55308..48cb40ab 100644
--- a/app/styles/layout/wiki.scss
+++ b/app/styles/layout/wiki.scss
@@ -24,10 +24,6 @@
position: relative;
.view-wiki-content {
&:hover {
- .wysiwyg {
- background: $whitish;
- cursor: pointer;
- }
.edit {
opacity: 1;
top: -1.5rem;
@@ -67,4 +63,12 @@
top: .4rem;
}
}
+ &.editable {
+ &:hover {
+ .wysiwyg {
+ background: $whitish;
+ cursor: pointer;
+ }
+ }
+ }
}
diff --git a/app/styles/modules/admin/admin-project-profile.scss b/app/styles/modules/admin/admin-project-profile.scss
index 0339fc66..cefec654 100644
--- a/app/styles/modules/admin/admin-project-profile.scss
+++ b/app/styles/modules/admin/admin-project-profile.scss
@@ -21,14 +21,15 @@
.privacy-settings {
display: flex;
margin-bottom: 2rem;
- div {
+ > div {
flex-basis: 0;
flex-grow: 1;
+ overflow: hidden;
+ position: relative;
&:first-child {
margin-right: .5rem;
}
}
- // TODO: This should change when public projects available
label {
@extend %title;
border: 1px solid $gray-light;
@@ -39,14 +40,22 @@
span {
color: $gray-light;
}
- // &:hover {
- // border: 1px solid $fresh-taiga;
- // }
}
- input:checked+label {
+ }
+ .privacy-project {
+ cursor: pointer;
+ height: 500px;
+ left: -10px;
+ opacity: 0;
+ position: absolute;
+ top: -10px;
+ width: 500px;
+ z-index: 999;
+ }
+ .privacy-project:checked {
+ + label {
background: $fresh-taiga;
border: 1px solid $fresh-taiga;
- cursor: default;
span {
color: $white;
}
diff --git a/app/styles/modules/admin/admin-roles.scss b/app/styles/modules/admin/admin-roles.scss
index 58203d80..daa55c21 100644
--- a/app/styles/modules/admin/admin-roles.scss
+++ b/app/styles/modules/admin/admin-roles.scss
@@ -101,5 +101,11 @@
opacity: 0;
}
}
+ input:disabled {
+ cursor: auto;
+ + div {
+ background-color: #ccc;
+ }
+ }
}
}