diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index e71ffcc1..955861d0 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -98,16 +98,26 @@ module.factory("$selectedText", ["$window", "$document", SelectedText]) CheckPermissionDirective = (projectService) -> render = ($el, project, permission) -> - $el.removeClass('hidden') if project.get('my_permissions').indexOf(permission) > -1 + if project && permission + $el.removeClass('hidden') if project.get('my_permissions').indexOf(permission) > -1 link = ($scope, $el, $attrs) -> $el.addClass('hidden') permission = $attrs.tgCheckPermission - $scope.$watch ( () -> + unwatch = $scope.$watch () -> return projectService.project - ), () -> - render($el, projectService.project, permission) if projectService.project + , () -> + return if !projectService.project + + render($el, projectService.project, permission) + unwatch() + + unObserve = $attrs.$observe "tgCheckPermission", (permission) -> + return if !permission + + render($el, projectService.project, permission) + unObserve() $scope.$on "$destroy", -> $el.off() diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index adee97c1..e10451eb 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -185,13 +185,13 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, promise = $repo.save($model.$modelValue) promise.then -> - $confirm.notify("success") watchers = _.map(watchers, (watcherId) -> $scope.usersById[watcherId]) renderWatchers(watchers) $rootscope.$broadcast("object:updated") promise.then null, -> $model.$modelValue.revert() + $confirm.notify("error") deleteWatcher = $qqueue.bindAdd (watcherIds) => item = $model.$modelValue.clone() @@ -200,7 +200,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, promise = $repo.save($model.$modelValue) promise.then -> - $confirm.notify("success") watchers = _.map(item.watchers, (watcherId) -> $scope.usersById[watcherId]) renderWatchers(watchers) $rootscope.$broadcast("object:updated") @@ -208,7 +207,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, item.revert() $confirm.notify("error") - renderWatchers = (watchers) -> ctx = { watchers: watchers @@ -235,12 +233,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, deleteWatcher(watcherIds) - $el.on "click", ".js-add-watcher", (event) -> - event.preventDefault() - return if not isEditable() - $scope.$apply -> - $rootscope.$broadcast("watcher:add", $model.$modelValue) - $scope.$on "watcher:added", (ctx, watcherId) -> watchers = _.clone($model.$modelValue.watchers, false) watchers.push(watcherId) @@ -285,7 +277,6 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template promise = $repo.save($model.$modelValue) promise.then -> currentLoading.finish() - $confirm.notify("success") renderAssignedTo($model.$modelValue) $rootscope.$broadcast("object:updated") promise.then null, -> @@ -295,13 +286,21 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template return promise - renderAssignedTo = (issue) -> - assignedToId = issue?.assigned_to - assignedTo = if assignedToId? then $scope.usersById[assignedToId] else null + renderAssignedTo = (assignedObject) -> + if assignedObject?.assigned_to_extra_info? + assignedTo = assignedObject?.assigned_to_extra_info + else + assignedTo = { + full_name_display: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED") + photo: "/#{window._version}/images/unnamed.png" + } + + isIocaine = assignedObject?.is_iocaine ctx = { assignedTo: assignedTo isEditable: isEditable() + isIocaine: isIocaine } html = $compile(template(ctx))($scope) $el.html(html) @@ -357,14 +356,14 @@ BlockButtonDirective = ($rootscope, $loading, $template) -> return if not item if isEditable() - $el.find('.item-block').addClass('editable') + $el.find('.item-block').addClass('is-editable') if item.is_blocked - $el.find('.item-block').hide() - $el.find('.item-unblock').show() + $el.find('.item-block').removeClass('is-active') + $el.find('.item-unblock').addClass('is-active') else - $el.find('.item-block').show() - $el.find('.item-unblock').hide() + $el.find('.item-block').addClass('is-active') + $el.find('.item-unblock').removeClass('is-active') $el.on "click", ".item-block", (event) -> event.preventDefault() @@ -711,13 +710,16 @@ ListItemTaskStatusDirective = -> module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective) -ListItemAssignedtoDirective = ($template) -> +ListItemAssignedtoDirective = ($template, $translate) -> template = $template.get("common/components/list-item-assigned-to-avatar.html", true) link = ($scope, $el, $attrs) -> bindOnce $scope, "usersById", (usersById) -> item = $scope.$eval($attrs.tgListitemAssignedto) - ctx = {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png"} + ctx = { + name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), + imgurl: "/#{window._version}/images/unnamed.png" + } member = usersById[item.assigned_to] if member @@ -728,7 +730,7 @@ ListItemAssignedtoDirective = ($template) -> return {link:link} -module.directive("tgListitemAssignedto", ["$tgTemplate", ListItemAssignedtoDirective]) +module.directive("tgListitemAssignedto", ["$tgTemplate", "$translate", ListItemAssignedtoDirective]) ListItemIssueStatusDirective = -> diff --git a/app/coffee/modules/common/estimation.coffee b/app/coffee/modules/common/estimation.coffee index 4df473bd..6cf8417f 100644 --- a/app/coffee/modules/common/estimation.coffee +++ b/app/coffee/modules/common/estimation.coffee @@ -31,7 +31,7 @@ module = angular.module("taigaCommon") ## User story estimation directive (for Lightboxes) ############################################################################# -LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $template, $compile) -> +LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $template, $compile) -> # Display the points of a US and you can edit it. # # Example: @@ -72,14 +72,15 @@ LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $ require: "ngModel" } -module.directive("tgLbUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgTemplate", "$compile", LbUsEstimationDirective]) +module.directive("tgLbUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgTemplate", + "$compile", LbUsEstimationDirective]) ############################################################################# ## User story estimation directive ############################################################################# -UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qqueue, $template, $compile) -> +UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $qqueue, $template, $compile) -> # Display the points of a US and you can edit it. # # Example: @@ -120,8 +121,8 @@ UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qq require: "ngModel" } -module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", "$tgTemplate", "$compile" - UsEstimationDirective]) +module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgQqueue", + "$tgTemplate", "$compile", UsEstimationDirective]) ############################################################################# @@ -145,7 +146,6 @@ EstimationsService = ($template, $qqueue, $repo, $confirm, $q) -> $qqueue.add () => onSuccess = => deferred.resolve() - $confirm.notify("success") onError = => $confirm.notify("error") @@ -247,4 +247,5 @@ EstimationsService = ($template, $qqueue, $repo, $confirm, $q) -> create: create } -module.factory("$tgEstimationsService", ["$tgTemplate", "$tgQqueue", "$tgRepo", "$tgConfirm", "$q", EstimationsService]) +module.factory("$tgEstimationsService", ["$tgTemplate", "$tgQqueue", "$tgRepo", "$tgConfirm", + "$q", EstimationsService]) diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index c085242f..a4146c7a 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -282,11 +282,10 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t issue.status = statusId currentLoading = $loading() - .target($el.find(".level-name")) + .target($el) .start() onSuccess = -> - $confirm.notify("success") $model.$setViewValue(issue) $rootScope.$broadcast("object:updated") currentLoading.finish() @@ -299,7 +298,7 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t $repo.save(issue).then(onSuccess, onError) - $el.on "click", ".status-data", (event) -> + $el.on "click", ".js-edit-status", (event) -> event.preventDefault() event.stopPropagation() return if not isEditable() @@ -373,7 +372,6 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $tem .start() onSuccess = -> - $confirm.notify("success") $model.$setViewValue(issue) $rootScope.$broadcast("object:updated") currentLoading.finish() @@ -462,7 +460,6 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, .start() onSuccess = -> - $confirm.notify("success") $model.$setViewValue(issue) $rootScope.$broadcast("object:updated") currentLoading.finish() @@ -551,7 +548,6 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, .start() onSuccess = -> - $confirm.notify("success") $model.$setViewValue(issue) $rootScope.$broadcast("object:updated") currentLoading.finish() diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index e290c5b6..a0d1f251 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -778,7 +778,7 @@ module.directive("tgIssueStatusInlineEdition", ["$tgRepo", "$tgTemplate", "$root ## Issue assigned to Directive ############################################################################# -IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> +IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> template = _.template(""" <%- name %>
<%- name %>
@@ -786,11 +786,15 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> link = ($scope, $el, $attrs) -> updateIssue = (issue) -> - ctx = {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png"} - member = $scope.usersById[issue.assigned_to] + ctx = { + name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), + imgurl: "/#{window._version}/images/unnamed.png" + } + + member = issue.assigned_to_extra_info if member - ctx.imgurl = member.photo ctx.name = member.full_name_display + ctx.imgurl = member.photo $el.find(".avatar").html(template(ctx)) $el.find(".issue-assignedto").attr('title', ctx.name) @@ -822,5 +826,5 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> return {link: link} -module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", +module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate" IssueAssignedToInlineEditionDirective]) diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 46af5382..f4edca5e 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -527,7 +527,7 @@ module.directive("tgKanbanWipLimit", KanbanWipLimitDirective) ## Kanban User Directive ############################################################################# -KanbanUserDirective = ($log, $compile) -> +KanbanUserDirective = ($log, $compile, $translate) -> template = _.template("""
class="not-clickable"<% } %>> @@ -555,9 +555,17 @@ KanbanUserDirective = ($log, $compile) -> render = (user) -> if user is undefined - ctx = {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png", clickable: clickable} + ctx = { + name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), + imgurl: "/#{window._version}/images/unnamed.png", + clickable: clickable + } else - ctx = {name: user.full_name_display, imgurl: user.photo, clickable: clickable} + ctx = { + name: user.full_name_display, + imgurl: user.photo, + clickable: clickable + } html = $compile(template(ctx))($scope) $el.html(html) @@ -588,4 +596,4 @@ KanbanUserDirective = ($log, $compile) -> return {link: link, require:"ngModel"} -module.directive("tgKanbanUserAvatar", ["$log", "$compile", KanbanUserDirective]) +module.directive("tgKanbanUserAvatar", ["$log", "$compile", "$translate", KanbanUserDirective]) diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index fb2ce8da..3d777a74 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -241,7 +241,7 @@ RelatedTasksDirective = ($repo, $rs, $rootscope) -> return {link: link} module.directive("tgRelatedTasks", ["$tgRepo", "$tgResources", "$rootScope", RelatedTasksDirective]) -RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> +RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> template = _.template(""" <%- name %>
<%- name %>
@@ -249,7 +249,10 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService link = ($scope, $el, $attrs) -> updateRelatedTask = (task) -> - ctx = {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png"} + ctx = { + name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), + imgurl: "/" + window._version + "/images/unnamed.png" + } member = $scope.usersById[task.assigned_to] if member ctx.imgurl = member.photo @@ -287,4 +290,5 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService return {link: link} -module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", RelatedTaskAssignedToInlineEditionDirective]) +module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate", + RelatedTaskAssignedToInlineEditionDirective]) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 44a216d3..757a0320 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -436,7 +436,7 @@ module.directive("tgTaskboardSquishColumn", ["$tgResources", TaskboardSquishColu ## Taskboard User Directive ############################################################################# -TaskboardUserDirective = ($log) -> +TaskboardUserDirective = ($log, $translate) -> clickable = false link = ($scope, $el, $attrs) -> @@ -447,9 +447,17 @@ TaskboardUserDirective = ($log) -> user = $scope.usersById[assigned_to] if user is undefined - _.assign($scope, {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png", clickable: clickable}) + _.assign($scope, { + name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), + imgurl: "/#{window._version}/images/unnamed.png", + clickable: clickable + }) else - _.assign($scope, {name: user.full_name_display, imgurl: user.photo, clickable: clickable}) + _.assign($scope, { + name: user.full_name_display, + imgurl: user.photo, + clickable: clickable + }) username_label.text($scope.name) @@ -484,4 +492,4 @@ TaskboardUserDirective = ($log) -> } -module.directive("tgTaskboardUserAvatar", ["$log", TaskboardUserDirective]) +module.directive("tgTaskboardUserAvatar", ["$log", "$translate", TaskboardUserDirective]) diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index c202bce5..b0c8f688 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -278,12 +278,11 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $co task.status = status currentLoading = $loading() - .target($el.find(".level-name")) + .target($el) .start() onSuccess = -> $model.$setViewValue(task) - $confirm.notify("success") $rootScope.$broadcast("object:updated") currentLoading.finish() @@ -293,7 +292,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $co $repo.save(task).then(onSuccess, onError) - $el.on "click", ".status-data", (event) -> + $el.on "click", ".js-edit-status", (event) -> event.preventDefault() event.stopPropagation() return if not isEditable() @@ -327,17 +326,8 @@ module.directive("tgTaskStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", " "$compile", "$translate", "$tgTemplate", TaskStatusButtonDirective]) -TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $compile) -> - template = _.template(""" -
- - -
- """) +TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $compile, $template) -> + template = $template.get("issue/iocaine-button.html", true) link = ($scope, $el, $attrs, $model) -> isEditable = -> @@ -367,7 +357,6 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue promise.then -> $model.$setViewValue(task) - $confirm.notify("success") $rootscope.$broadcast("object:updated") promise.then null, -> @@ -395,4 +384,4 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue } module.directive("tgTaskIsIocaineButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", - "$compile", TaskIsIocaineButtonDirective]) + "$compile", "$tgTemplate", TaskIsIocaineButtonDirective]) diff --git a/app/coffee/modules/userstories/detail.coffee b/app/coffee/modules/userstories/detail.coffee index 10f60741..08468dc8 100644 --- a/app/coffee/modules/userstories/detail.coffee +++ b/app/coffee/modules/userstories/detail.coffee @@ -277,54 +277,6 @@ UsStatusDisplayDirective = ($template, $compile) -> module.directive("tgUsStatusDisplay", ["$tgTemplate", "$compile", UsStatusDisplayDirective]) - -############################################################################# -## User story related tasts progress splay Directive -############################################################################# - -UsTasksProgressDisplayDirective = ($template, $compile) -> - # Display a progress bar with the stats of completed tasks. - # - # Example: - # tg-us-tasks-progress-display(ng-model="tasks") - # - # Requirements: - # - Task object list (ng-model) - # - scope.taskStatusById object - - link = ($scope, $el, $attrs) -> - render = (tasks) -> - totalTasks = tasks.length - totalClosedTasks = _.filter(tasks, (task) => $scope.taskStatusById[task.status].is_closed).length - - progress = if totalTasks > 0 then 100 * totalClosedTasks / totalTasks else 0 - - _.assign($scope, { - totalTasks: totalTasks - totalClosedTasks: totalClosedTasks - progress: progress, - style: { - width: progress + "%" - } - }) - - $scope.$watch $attrs.ngModel, (tasks) -> - render(tasks) if tasks? - - $scope.$on "$destroy", -> - $el.off() - - return { - templateUrl: "us/us-task-progress.html" - link: link - restrict: "EA" - require: "ngModel" - scope: true - } - -module.directive("tgUsTasksProgressDisplay", ["$tgTemplate", "$compile", UsTasksProgressDisplayDirective]) - - ############################################################################# ## User story status button directive ############################################################################# @@ -365,11 +317,10 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp $.fn.popover().closeAll() currentLoading = $loading() - .target($el.find(".level-name")) + .target($el) .start() onSuccess = -> - $confirm.notify("success") $model.$setViewValue(us) $rootScope.$broadcast("object:updated") currentLoading.finish() @@ -380,7 +331,7 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp $repo.save(us).then(onSuccess, onError) - $el.on "click", ".status-data", (event) -> + $el.on "click", ".js-edit-status", (event) -> event.preventDefault() event.stopPropagation() return if not isEditable() @@ -425,10 +376,6 @@ UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qq return $scope.project.my_permissions.indexOf("modify_us") != -1 render = (us) -> - if not canEdit() and not us.team_requirement - $el.html("") - return - ctx = { canEdit: canEdit() isRequired: us.team_requirement @@ -489,10 +436,6 @@ UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $ return $scope.project.my_permissions.indexOf("modify_us") != -1 render = (us) -> - if not canEdit() and not us.client_requirement - $el.html("") - return - ctx = { canEdit: canEdit() isRequired: us.client_requirement diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 37455848..9bc7d330 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -24,6 +24,8 @@ "FROM": "from", "TO": "to", "CLOSE": "close", + "BLOCK": "Block this User Story if it has a dependency that can not be satisfied", + "UNBLOCK": "Unblock this User Story", "BLOCKED_NOTE": "Why is this user story blocked?", "BLOCKED_REASON": "Please explain the reason", "GO_HOME": "Take me home", @@ -36,6 +38,8 @@ "EXTERNAL_USER": "an external user", "GENERIC_ERROR": "One of our Oompa Loompas says {{error}}.", "IOCAINE_TEXT": "Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!", + "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", + "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "CAPSLOCK_WARNING": "Be careful! You're writing with capital letters and this input is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "This value seems to be invalid.", @@ -150,6 +154,7 @@ "OPEN": "Open" }, "WATCHERS": { + "WATCHERS": "Watchers", "ADD": "Add watchers", "TITLE_ADD": "Add a project member to the watchers list", "DELETE": "Delete watcher", diff --git a/app/modules/components/watch-button/watch-button-ticket.jade b/app/modules/components/watch-button/watch-button-ticket.jade new file mode 100644 index 00000000..e54d36fd --- /dev/null +++ b/app/modules/components/watch-button/watch-button-ticket.jade @@ -0,0 +1,37 @@ +div.ticket-watch-title( + title="{{ 'COMMON.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.watchers.length||0}:'messageformat' }}", + tg-loading="vm.loading" +) {{ vm.item.watchers.length }} {{'COMMON.WATCHERS.WATCHERS' | translate}} + +div.ticket-watch-inner + a.ticket-watch-button( + href="" + title="{{ 'COMMON.WATCH_BUTTON.BUTTON_TITLE' | translate }}" + ng-if="::vm.user" + ng-click="vm.toggleWatch()" + ng-class="{'active': vm.item.is_watcher, 'is-hover': vm.item.is_watcher && vm.isMouseOver}" + ng-mouseover="vm.showTextWhenMouseIsOver()" + ng-mouseleave="vm.showTextWhenMouseIsLeave()" + ) + span.track-icon + include ../../../svg/watch.svg + span( + ng-if="!vm.item.is_watcher", + translate="COMMON.WATCH_BUTTON.WATCH" + ) + span( + ng-if="vm.item.is_watcher && !vm.isMouseOver", + translate="COMMON.WATCH_BUTTON.WATCHING" + ) + span( + ng-if="vm.item.is_watcher && vm.isMouseOver", + translate="COMMON.WATCH_BUTTON.UNWATCH" + ) + + a.add-watcher( + href="" + title="{{'COMMON.WATCHERS.TITLE_ADD' | translate}}" + ng-click="vm.openWatchers()" + tg-check-permission="{{vm.getPerms()}}" + ) + span + {{'COMMON.WATCHERS.ADD' | translate}} diff --git a/app/modules/components/watch-button/watch-button.controller.coffee b/app/modules/components/watch-button/watch-button.controller.coffee index 39b16f57..99514424 100644 --- a/app/modules/components/watch-button/watch-button.controller.coffee +++ b/app/modules/components/watch-button/watch-button.controller.coffee @@ -20,9 +20,10 @@ class WatchButtonController @.$inject = [ "tgCurrentUserService", + "$rootScope" ] - constructor: (@currentUserService) -> + constructor: (@currentUserService, @rootScope) -> @.user = @currentUserService.getUser() @.isMouseOver = false @.loading = false @@ -33,6 +34,22 @@ class WatchButtonController showTextWhenMouseIsLeave: -> @.isMouseOver = false + openWatchers: -> + @rootScope.$broadcast("watcher:add", @.item) + + getPerms: -> + return "" if !@.item + + name = @.item._name + + perms = { + userstories: 'modify_us', + issues: 'modify_issue', + tasks: 'modify_task' + } + + return perms[name] + toggleWatch: -> @.loading = true diff --git a/app/modules/components/watch-button/watch-button.controller.spec.coffee b/app/modules/components/watch-button/watch-button.controller.spec.coffee index db06465b..41e95efb 100644 --- a/app/modules/components/watch-button/watch-button.controller.spec.coffee +++ b/app/modules/components/watch-button/watch-button.controller.spec.coffee @@ -100,3 +100,24 @@ describe "WatchButton", -> expect(ctrl.loading).to.be.false; done() + + + it "get permissions", () -> + $scope = $rootScope.$new() + + ctrl = $controller("WatchButton", $scope, { + item: {_name: 'tasks'} + }) + + perm = ctrl.getPerms() + expect(perm).to.be.equal('modify_task') + + ctrl.item = {_name: 'issues'} + + perm = ctrl.getPerms() + expect(perm).to.be.equal('modify_issue') + + ctrl.item = {_name: 'userstories'} + + perm = ctrl.getPerms() + expect(perm).to.be.equal('modify_us') diff --git a/app/modules/components/watch-button/watch-button.directive.coffee b/app/modules/components/watch-button/watch-button.directive.coffee index 12a9ac7b..a5797950 100644 --- a/app/modules/components/watch-button/watch-button.directive.coffee +++ b/app/modules/components/watch-button/watch-button.directive.coffee @@ -27,7 +27,8 @@ WatchButtonDirective = -> onUnwatch: "=" } controllerAs: "vm", - templateUrl: "components/watch-button/watch-button.html", + templateUrl: (item, attributes) -> + return "components/watch-button/watch-button-"+attributes.environment+".html" } angular.module("taigaComponents").directive("tgWatchButton", WatchButtonDirective) diff --git a/app/modules/navigation-bar/navigation-bar.scss b/app/modules/navigation-bar/navigation-bar.scss index 469ecb8d..440784c0 100644 --- a/app/modules/navigation-bar/navigation-bar.scss +++ b/app/modules/navigation-bar/navigation-bar.scss @@ -32,7 +32,9 @@ $dropdown-width: 350px; } svg { height: 1.6rem; + max-height: 1.6rem; max-width: 2rem; + width: 1.6rem; } path { fill: $white; @@ -79,7 +81,9 @@ $dropdown-width: 350px; } svg { height: 1.2rem; + max-height: 1.2rem; max-width: 1.2rem; + width: 1.2rem; path { fill: $top-icon-color; transition: all .2s; diff --git a/app/partials/common/components/assigned-to.jade b/app/partials/common/components/assigned-to.jade index 7ad68ab3..79ae8748 100644 --- a/app/partials/common/components/assigned-to.jade +++ b/app/partials/common/components/assigned-to.jade @@ -1,6 +1,10 @@ <% if (assignedTo) { %> -.user-avatar +.user-avatar(class!="<% if(isIocaine){ %> is-iocaine <% }; %>") img(src!="<%- assignedTo.photo %>", alt!="<%- assignedTo.full_name_display %>") + <% if(isIocaine){ %> + .iocaine-symbol(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}") + include ../../../svg/iocaine.svg + <% }; %> <% } %> .assigned-to @@ -9,11 +13,7 @@ a(href="" title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}", class!="user-assigned <% if(isEditable){ %>editable<% }; %>") span.assigned-name - <% if (assignedTo) { %> <%- assignedTo.full_name_display %> - <% } else { %> - | {{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }} - <% } %> <% if(isEditable){ %> span.icon.icon-arrow-bottom <% }; %> diff --git a/app/partials/common/components/block-button.jade b/app/partials/common/components/block-button.jade index 8dc4e055..631d288c 100644 --- a/app/partials/common/components/block-button.jade +++ b/app/partials/common/components/block-button.jade @@ -1,4 +1,10 @@ -a(href="#", class="button button-gray item-block") - span(translate="COMMON.BLOCK") -a(href="#", class="button button-red item-unblock") - span(translate="COMMON.UNBLOCK") +a.button-gray.item-block( + href="" + title="{{ 'COMMON.BLOCK' | translate }}" +) + include ../../../svg/lock.svg +a.button-red.item-unblock( + href="" + title="{{ 'COMMON.UNBLOCK' | translate }}" +) + include ../../../svg/unlock.svg diff --git a/app/partials/common/components/created-by.jade b/app/partials/common/components/created-by.jade index 3689afef..8486d0fa 100644 --- a/app/partials/common/components/created-by.jade +++ b/app/partials/common/components/created-by.jade @@ -1,9 +1,17 @@ -.user-avatar - a(href="{{url}}", title="{{owner.full_name_display}}") - img(src="{{owner.photo}}", alt="{{owner.full_name_display}}") - .created-by - a(href="{{url}}", title="{{owner.full_name_display}}") - span.created-title(translate="COMMON.CREATED_BY", translate-values="{ 'fullDisplayName': owner.full_name_display}") - span.created-date - | {{date}} + a.created-title( + href="{{url}}" + title="{{owner.full_name_display}}" + translate="COMMON.CREATED_BY" + translate-values="{ 'fullDisplayName': owner.full_name_display}" + ) + .created-date {{date}} +.user-avatar + a( + href="{{url}}" + title="{{owner.full_name_display}}" + ) + img( + src="{{owner.photo}}" + alt="{{owner.full_name_display}}" + ) diff --git a/app/partials/common/components/delete-button.jade b/app/partials/common/components/delete-button.jade index cc325950..22f6ee5b 100644 --- a/app/partials/common/components/delete-button.jade +++ b/app/partials/common/components/delete-button.jade @@ -1,2 +1,5 @@ -a.button-red.button-delete(href="") - span(translate="COMMON.DELETE") +a.button-red.button-delete( + href="" + title="{{ 'COMMON.DELETE' | translate }}" +) + include ../../../svg/trash.svg diff --git a/app/partials/common/components/status-display.jade b/app/partials/common/components/status-display.jade index 098ffa32..553ea3b1 100644 --- a/app/partials/common/components/status-display.jade +++ b/app/partials/common/components/status-display.jade @@ -3,5 +3,3 @@ span(translate="COMMON.STATUS.CLOSED") <% } else { %> span(translate="COMMON.STATUS.OPEN") <% } %> -span(class="detail-status", style!="color:<%- status.color %>") - | <%- status.name %> diff --git a/app/partials/common/components/watchers.jade b/app/partials/common/components/watchers.jade index 31e4ea94..fcbe398d 100644 --- a/app/partials/common/components/watchers.jade +++ b/app/partials/common/components/watchers.jade @@ -18,12 +18,3 @@ <% }; %> <% } %> <% }); %> - -<% if(isEditable){ %> -a.add-watcher.js-add-watcher( - href="" - title="{{'COMMON.WATCHERS.TITLE_ADD' | translate}}" -) - span.icon.icon-plus - span(translate="COMMON.WATCHERS.ADD") -<% }; %> diff --git a/app/partials/common/estimation/us-estimation-points-per-role.jade b/app/partials/common/estimation/us-estimation-points-per-role.jade index 904d6b4a..86bf489c 100644 --- a/app/partials/common/estimation/us-estimation-points-per-role.jade +++ b/app/partials/common/estimation/us-estimation-points-per-role.jade @@ -1,9 +1,12 @@ ul.points-per-role + <% _.each(roles, function(role) { %> + li.ticket-role-points.total(class!="<% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") + span.points + <%- role.points %> + span.icon-arrow-bottom + span.role + <%- role.name %> + <% }); %> li.ticket-role-points.total span.points <%- totalPoints %> span.role(translate="US.TOTAL_POINTS") - <% _.each(roles, function(role) { %> - li.ticket-role-points(class!="total <% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") - span.points <%- role.points %> - span.role <%- role.name %> - <% }); %> diff --git a/app/partials/common/tag/tag-line.jade b/app/partials/common/tag/tag-line.jade index c7df1c3a..d6bc320a 100644 --- a/app/partials/common/tag/tag-line.jade +++ b/app/partials/common/tag/tag-line.jade @@ -4,4 +4,4 @@ a(href="#", class="add-tag hidden", title="{{'COMMON.TAGS.ADD' | translate}}") span.add-tag-text(translate="COMMON.TAGS.ADD") input(type="text", placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}", class="tag-input hidden") -a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") \ No newline at end of file +a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") diff --git a/app/partials/issue/iocaine-button.jade b/app/partials/issue/iocaine-button.jade new file mode 100644 index 00000000..fecc54d9 --- /dev/null +++ b/app/partials/issue/iocaine-button.jade @@ -0,0 +1,11 @@ +fieldset(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}") + label.button-gray.is-iocaine( + for="is-iocaine" + class!="<% if(isEditable){ %>is-editable<% }; %> <% if(isIocaine){ %>active<% }; %>" + ) + include ../../svg/iocaine.svg + input( + type="checkbox" + id="is-iocaine" + name="is-iocaine" + ) diff --git a/app/partials/issue/issues-detail.jade b/app/partials/issue/issues-detail.jade index 06e00bc0..da3a33e5 100644 --- a/app/partials/issue/issues-detail.jade +++ b/app/partials/issue/issues-detail.jade @@ -57,8 +57,9 @@ div.wrapper( tg-bo-href="nextUrl" title="{{'ISSUES.TITLE_NEXT_ISSUE' | translate}}" ) - - div.tags-block(tg-tag-line, ng-model="issue", required-perm="modify_issue") + .subheader + div.tags-block(tg-tag-line, ng-model="issue", required-perm="modify_issue") + tg-created-by-display.ticket-created-by(ng-model="issue") section.duty-content(tg-editable-description, tg-editable-wysiwyg, ng-model="issue", required-perm="modify_issue") @@ -79,35 +80,49 @@ div.wrapper( tg-history(ng-model="issue", type="issue") sidebar.menu-secondary.sidebar.ticket-data - section.status - .ticket-title(tg-issue-status-display, ng-model="issue") - tg-created-by-display.ticket-created-by(ng-model="issue") + + .ticket-header + span.ticket-title( + tg-issue-status-display + ng-model="issue" + ) + span.detail-status( + tg-issue-status-button + ng-model="issue" + ) + + //tg-created-by-display.ticket-created-by(ng-model="issue") + div.ticket-data-container div.ticket-status(tg-issue-type-button, ng-model="issue") div.ticket-status(tg-issue-severity-button, ng-model="issue") div.ticket-status(tg-issue-priority-button, ng-model="issue") - div.ticket-status(tg-issue-status-button, ng-model="issue") section.ticket-assigned-to(tg-assigned-to, ng-model="issue", required-perm="modify_issue") - section.track-buttons-container.ticket-track-buttons - - div.watch-button - tg-watch-button( - item="issue" - on-watch="ctrl.onWatch" - on-unwatch="ctrl.onUnwatch" - ) - + section.ticket-watch-buttons + div.ticket-watch( + tg-watch-button + item="issue" + data-environment="ticket" + on-watch="ctrl.onWatch" + on-unwatch="ctrl.onUnwatch" + ) div.ticket-watchers( tg-watchers ng-model="issue" - required-perm="modify_issue" + required-perm="modify_us" ) section.ticket-detail-settings - tg-promote-issue-to-us-button(tg-check-permission="add_us", ng-model="issue") - tg-block-button(tg-check-permission="modify_issue", ng-model="issue") + tg-promote-issue-to-us-button( + tg-check-permission="add_us", + ng-model="issue" + ) + tg-block-button( + tg-check-permission="modify_issue", + ng-model="issue" + ) tg-delete-button( tg-check-permission="delete_issue", on-delete-title="{{'ISSUES.ACTION_DELETE' | translate}}", diff --git a/app/partials/issue/issues-status-button.jade b/app/partials/issue/issues-status-button.jade index 6d56fae8..37651385 100644 --- a/app/partials/issue/issues-status-button.jade +++ b/app/partials/issue/issues-status-button.jade @@ -1,15 +1,20 @@ -div(class!="status-data <% if(editable){ %>clickable<% }%>") - span(class="level", style!="background-color:<%- status.color %>") - span(class="status-status") <%- status.name %> +span.detail-status-inner.js-edit-status( + class!="<% if(editable){ %>clickable<% }%>" + style!="background-color:<%- status.color %>" + ng-click="editStatus()" +) + span <%- status.name %> <% if(editable){ %> - span(class="icon icon-arrow-bottom") - <% } %> - span(class="level-name", translate="COMMON.FIELDS.STATUS") - - ul(class="popover pop-status") + span.icon.icon-arrow-bottom + <% }%> + + ul.pop-status <% _.each(statuses, function(st) { %> li - a(href="", class="status", title!="<%- st.name %>", - data-status-id!="<%- st.id %>") + a.status( + href="" + title!="<%- st.name %>" + data-status-id!="<%- st.id %>" + ) | <%- st.name %> <% }); %> diff --git a/app/partials/issue/promote-issue-to-us-button.jade b/app/partials/issue/promote-issue-to-us-button.jade index 6d56172b..6eafe624 100644 --- a/app/partials/issue/promote-issue-to-us-button.jade +++ b/app/partials/issue/promote-issue-to-us-button.jade @@ -1,2 +1,2 @@ -a(class="button button-gray editable", tg-check-permission="add_us") - span(translate="ISSUES.ACTION_PROMOTE_TO_US") +a.promote-button.is-editable(tg-check-permission="add_us") + include ../../svg/promote.svg diff --git a/app/partials/task/task-detail.jade b/app/partials/task/task-detail.jade index c8e7dfb6..f9570518 100644 --- a/app/partials/task/task-detail.jade +++ b/app/partials/task/task-detail.jade @@ -72,8 +72,9 @@ div.wrapper( tg-bo-href="nextUrl" title="{{'TASK.NEXT' | translate}}" ) - - div.tags-block(tg-tag-line, ng-model="task", required-perm="modify_task") + .subheader + div.tags-block(tg-tag-line, ng-model="task", required-perm="modify_task") + tg-created-by-display.ticket-created-by(ng-model="task") section.duty-content(tg-editable-description, tg-editable-wysiwyg, ng-model="task", required-perm="modify_task") @@ -95,29 +96,30 @@ div.wrapper( sidebar.menu-secondary.sidebar.ticket-data - section.status - - .ticket-title(tg-task-status-display, ng-model="task") - - .ticket-created-by(tg-created-by-display, ng-model="task") - - .ticket-data-container - .ticket-status(tg-task-status-button, ng-model="task") + .ticket-header + span.ticket-title( + tg-task-status-display + ng-model="task" + ) + span.detail-status( + tg-task-status-button + ng-model="task" + ) section.ticket-assigned-to(tg-assigned-to, ng-model="task", required-perm="modify_task") - section.track-buttons-container.ticket-track-buttons - div.watch-button - tg-watch-button( - item="task" - on-watch="ctrl.onWatch" - on-unwatch="ctrl.onUnwatch" - ) - + section.ticket-watch-buttons + div.ticket-watch( + tg-watch-button + item="task" + data-environment="ticket" + on-watch="ctrl.onWatch" + on-unwatch="ctrl.onUnwatch" + ) div.ticket-watchers( - tg-watchers, - ng-model="task", - required-perm="modify_task" + tg-watchers + ng-model="task" + required-perm="modify_us" ) section.ticket-detail-settings diff --git a/app/partials/us/us-client-requirement-button.jade b/app/partials/us/us-client-requirement-button.jade index dc269cbc..b8d7a506 100644 --- a/app/partials/us/us-client-requirement-button.jade +++ b/app/partials/us/us-client-requirement-button.jade @@ -1,4 +1,11 @@ -label(for="client-requirement", - class!="button button-gray client-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>", translate="US.FIELDS.CLIENT_REQUIREMENT") - -input(type="checkbox", id="client-requirement", name="client-requirement") \ No newline at end of file +label.button-gray.client-requirement( + for="client-requirement" + class!="<% if(canEdit){ %>is-editable<% }; %> <% if(isRequired){ %>active<% }; %>" + title="{{ 'COMMON.CLIENT_REQUIREMENT' | translate }}" +) + include ../../svg/client-requirement.svg +input( + type="checkbox" + id="client-requirement" + name="client-requirement" +) diff --git a/app/partials/us/us-detail.jade b/app/partials/us/us-detail.jade index 1b845b7a..65b6f893 100644 --- a/app/partials/us/us-detail.jade +++ b/app/partials/us/us-detail.jade @@ -65,8 +65,9 @@ div.wrapper( tg-bo-href="nextUrl" title="{{'US.NEXT' | translate}}" ) - - div.tags-block(tg-tag-line, ng-model="us", required-perm="modify_us") + .subheader + .tags-block(tg-tag-line, ng-model="us", required-perm="modify_us") + tg-created-by-display.ticket-created-by(ng-model="us") section.duty-content(tg-editable-description, tg-editable-wysiwyg, ng-model="us", required-perm="modify_us") @@ -92,24 +93,18 @@ div.wrapper( ) sidebar.menu-secondary.sidebar.ticket-data - section - div.ticket-title( + + section.ticket-header + span.ticket-title( tg-us-status-display ng-model="us" ) + span.detail-status( + tg-us-status-button + ng-model="us" + ) - tg-created-by-display.ticket-created-by(ng-model="us") - - //div.ticket-detail-progress-bar(tg-us-tasks-progress-display, ng-model="tasks") - - div.ticket-data-container - div.ticket-status( - tg-us-status-button - ng-model="us" - ) - - section.ticket-estimation - tg-us-estimation(ng-model="us") + tg-us-estimation.ticket-estimation(ng-model="us") section.ticket-assigned-to( tg-assigned-to @@ -117,20 +112,21 @@ div.wrapper( required-perm="modify_us" ) - section.track-buttons-container.ticket-track-buttons - div.watch-button - tg-watch-button( - item="us" - on-watch="ctrl.onWatch" - on-unwatch="ctrl.onUnwatch" - ) - + section.ticket-watch-buttons + div.ticket-watch( + tg-watch-button + item="us" + data-environment="ticket" + on-watch="ctrl.onWatch" + on-unwatch="ctrl.onUnwatch" + ) div.ticket-watchers( tg-watchers ng-model="us" required-perm="modify_us" ) + section.ticket-detail-settings tg-us-team-requirement-button(ng-model="us") tg-us-client-requirement-button(ng-model="us") diff --git a/app/partials/us/us-status-button.jade b/app/partials/us/us-status-button.jade index 7a3ba3b5..64f9caaf 100644 --- a/app/partials/us/us-status-button.jade +++ b/app/partials/us/us-status-button.jade @@ -1,14 +1,19 @@ -div(class!="status-data <% if(editable){ %>clickable<% }%>") - span.level(style!="background-color:<%- status.color %>") - span.status-status <%- status.name %> +span.detail-status-inner.js-edit-status( + class!="<% if(editable){ %>clickable<% }%>" + style!="background-color:<%- status.color %>" +) + span <%- status.name %> <% if(editable){ %> span.icon.icon-arrow-bottom <% }%> - span.level-name(translate="COMMON.FIELDS.STATUS") - ul.popover.pop-status + ul.pop-status.popover <% _.each(statuses, function(st) { %> li - a(href="", class="status", title!="<%- st.name %>", data-status-id!="<%- st.id %>") + a.status( + href="" + title!="<%- st.name %>" + data-status-id!="<%- st.id %>" + ) | <%- st.name %> <% }); %> diff --git a/app/partials/us/us-task-progress.jade b/app/partials/us/us-task-progress.jade deleted file mode 100644 index df2f8b7c..00000000 --- a/app/partials/us/us-task-progress.jade +++ /dev/null @@ -1,2 +0,0 @@ -.current-progress(ng-style='style') -div.tasks-completed(translate="US.TASK_COMPLETED", translate-values='{ totalTasks: totalTasks, totalClosedTasks: totalClosedTasks}') diff --git a/app/partials/us/us-team-requirement-button.jade b/app/partials/us/us-team-requirement-button.jade index e1520364..e34338b1 100644 --- a/app/partials/us/us-team-requirement-button.jade +++ b/app/partials/us/us-team-requirement-button.jade @@ -1,3 +1,12 @@ -label(for="team-requirement", class!="button button-gray team-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>", translate="US.FIELDS.TEAM_REQUIREMENT") +label.button-gray.team-requirement( + for="team-requirement" + class!=" <% if(canEdit){ %>is-editable<% }; %> <% if(isRequired){ %>active<% }; %>" + title="{{ 'COMMON.TEAM_REQUIREMENT' | translate }}" +) + include ../../svg/team-requirement.svg -input(type="checkbox", id="team-requirement", name="team-requirement") \ No newline at end of file +input( + type="checkbox" + id="team-requirement" + name="team-requirement" +) diff --git a/app/styles/components/created-by.scss b/app/styles/components/created-by.scss index 734bd5f9..60d6470a 100644 --- a/app/styles/components/created-by.scss +++ b/app/styles/components/created-by.scss @@ -1,29 +1,45 @@ .ticket-created-by { display: flex; - margin-bottom: 1rem; - margin-top: .5rem; - position: relative; + justify-content: flex-end; + @include breakpoint(laptop) { + justify-content: flex-start; + margin-bottom: .5rem; + } .user-avatar { - flex-basis: 3rem; + flex-basis: 2rem; flex-grow: 0; - margin-right: .5rem; + margin-left: .5rem; + @include breakpoint(laptop) { + margin-left: 0; + margin-right: .5rem; + order: 1; + } img { width: 100%; } } .created-by { + @include breakpoint(laptop) { + order: 2; + } .created-title, .created-date { @extend %light; @extend %small; color: $gray; display: block; - line-height: 1.5; + text-align: right; + @include breakpoint(laptop) { + text-align: left; + } } .created-title { color: $primary; - &.editable { - cursor: pointer; + } + .created-date { + margin-left: .5rem; + @include breakpoint(laptop) { + margin-left: 0; } } } diff --git a/app/styles/components/estimation.scss b/app/styles/components/estimation.scss index 3f50666d..fcc98acd 100644 --- a/app/styles/components/estimation.scss +++ b/app/styles/components/estimation.scss @@ -1,48 +1,56 @@ -%estimation { +@mixin estimation { .points-per-role { display: flex; - flex-wrap: wrap; - justify-content: center; + flex-direction: column; } .ticket-role-points { - background: rgba($gray-light, .1); - border-radius: 2px; - color: rgba($grayer, .3); - flex-basis: 20%; - flex-grow: 1; - flex-shrink: 0; - margin: .1rem; - padding: .5rem 0 .1rem; + background: rgba($gray-light, .2); + color: $gray-light; + display: flex; + flex: 1; + justify-content: space-between; + margin-bottom: .1rem; + padding: .5rem 1rem; position: relative; - text-align: center; transition: color .3s linear; - &.active { - background: rgba($primary-light, .9); - color: $whitish; - } - &:first-child { - background: rgba($grayer, .25); - border-radius: 0; - color: $whitish; + &.clickable { + &:hover, + &.active { + background: rgba($primary-light, .9); + color: $whitish; + .points, + .role, + .icon-arrow-bottom { + color: $whitish; + } + } } &:last-child { - border: 0; + background: rgba($primary-dark, .5); + border-bottom: 0; + color: $whitish; + .points, + .role, + .icon-arrow-bottom { + @extend %text; + color: $whitish; + } + } + .icon-arrow-bottom { + color: $gray-light; + margin-left: .25rem; + vertical-align: middle; } .points { - @extend %larger; - @extend %text; - display: block; - text-align: center; + @extend %light; + color: $grayer; } .role { - @extend %small; - @include ellipsis(90%); - display: inline-block; - text-align: center; + @extend %light; } } .popover { - @include popover(200px, $top: 105%, $left: 35%, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 10px, $arrow-height: 10px); + @include popover(200px, $top: 100%, $left: .5rem, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 10px, $arrow-height: 10px); li { display: inline-block; width: 23%; @@ -57,11 +65,11 @@ } } &.fix { - @include popover(200px, $top: 105%, $left: -160px, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 90%, $arrow-height: 10px); + @include popover(200px, $top: 100%, $left: -160px, $arrow-width: 10px, $arrow-top: -5px, $arrow-left: 90%, $arrow-height: 10px); } } } .ticket-estimation { - @extend %estimation; + @include estimation; } diff --git a/app/styles/components/summary.scss b/app/styles/components/summary.scss index cd25dc2f..3c25c075 100644 --- a/app/styles/components/summary.scss +++ b/app/styles/components/summary.scss @@ -63,6 +63,8 @@ $summary-background: $grayer; svg { fill: $black; height: 100%; + max-height: 2rem; + max-width: 2rem; transition: all .2s; width: 100%; } diff --git a/app/styles/components/tag.scss b/app/styles/components/tag.scss index 7cf06594..d1fcff0b 100644 --- a/app/styles/components/tag.scss +++ b/app/styles/components/tag.scss @@ -38,8 +38,9 @@ display: inline-block; } input { + margin-right: .25rem; padding: .4rem; - width: 14rem; + width: 10rem; } .tag { @extend %small; diff --git a/app/styles/components/user-list.scss b/app/styles/components/user-list.scss index 6247ddff..299014ae 100644 --- a/app/styles/components/user-list.scss +++ b/app/styles/components/user-list.scss @@ -1,11 +1,11 @@ -%user-list { +@mixin user-list { .user-list-single { align-content: center; align-items: center; background: transparent; border-bottom: 1px solid $whitish; display: flex; - padding: .5rem .5rem .3rem; + padding: .25rem 0; vertical-align: middle; &:last-child { @@ -28,7 +28,7 @@ } .assigned-to-list { - @extend %user-list; + @include user-list; margin-top: 1rem; .user-list-single { &:hover, @@ -59,7 +59,7 @@ } .ticket-watchers { - @extend %user-list; + @include user-list; margin-top: 1rem; .user-list-single { &:hover { diff --git a/app/styles/core/elements.scss b/app/styles/core/elements.scss index 973d8346..c7d57631 100644 --- a/app/styles/core/elements.scss +++ b/app/styles/core/elements.scss @@ -47,6 +47,11 @@ sup { cursor: move; } +svg { + max-height: 1rem; + max-width: 1rem; +} + //Datepicker .pika-single { // scss-lint:disable ImportantRule diff --git a/app/styles/dependencies/mixins.scss b/app/styles/dependencies/mixins.scss index a77f687e..2eb9425e 100644 --- a/app/styles/dependencies/mixins.scss +++ b/app/styles/dependencies/mixins.scss @@ -133,8 +133,8 @@ } .icon { svg { - max-height: 1rem; - max-width: 1rem; + height: 1rem; + width: 1rem; } path { fill: currentcolor; diff --git a/app/styles/layout/auth.scss b/app/styles/layout/auth.scss index 393e1eb6..468ba9f2 100644 --- a/app/styles/layout/auth.scss +++ b/app/styles/layout/auth.scss @@ -18,6 +18,10 @@ padding: 0 33%; text-align: center; width: 100%; + svg { + max-height: 100%; + max-width: 100%; + } } .logo { @extend %xxlarge; diff --git a/app/styles/layout/ticket-detail.scss b/app/styles/layout/ticket-detail.scss index fcd90e4d..061a81f5 100644 --- a/app/styles/layout/ticket-detail.scss +++ b/app/styles/layout/ticket-detail.scss @@ -1,5 +1,5 @@ .us-story-main-data { - margin-bottom: 2rem; + margin-bottom: 1rem; header { align-content: center; align-items: stretch; @@ -165,6 +165,30 @@ } } +.subheader { + display: flex; + justify-content: space-between; + @include breakpoint(laptop) { + flex-direction: column; + justify-content: flex-start; + } + .ticket-created-by { + flex: 1; + flex-basis: 250px; + @include breakpoint(laptop) { + flex: 0; + order: 1; + } + } + .tags-block { + flex: 3; + @include breakpoint(laptop) { + flex: 0; + order: 2; + } + } +} + .duty-content { @include cursor-progress; position: relative; diff --git a/app/styles/modules/backlog/sprints.scss b/app/styles/modules/backlog/sprints.scss index 40e4a071..7ba4d2cb 100644 --- a/app/styles/modules/backlog/sprints.scss +++ b/app/styles/modules/backlog/sprints.scss @@ -17,6 +17,8 @@ } svg { height: 1.4rem; + max-height: 1.4rem; + max-width: 1.5rem; width: 1.5rem; } path { diff --git a/app/styles/modules/common/assigned-to.scss b/app/styles/modules/common/assigned-to.scss index 207ae322..15e7d2b9 100644 --- a/app/styles/modules/common/assigned-to.scss +++ b/app/styles/modules/common/assigned-to.scss @@ -1,7 +1,10 @@ .ticket-assigned-to { align-items: center; + border-bottom: 1px solid $gray-light; + border-top: 1px solid $gray-light; display: flex; margin-bottom: 1rem; + padding: 1rem 0; position: relative; &:hover { .assigned-to { @@ -18,11 +21,31 @@ max-width: 2rem; } .user-avatar { - flex-basis: 4rem; + flex-basis: 3rem; flex-shrink: 0; + position: relative; img { width: 100%; } + &.is-iocaine { + img { + filter: hue-rotate(150deg) saturate(200%); + } + } + .iocaine-symbol { + left: -.5rem; + position: absolute; + top: -.75rem; + z-index: 9; + svg { + background: $grayer; + border-radius: .25rem; + fill: $white; + min-height: 1.75rem; + min-width: 1.75rem; + padding: .25rem; + } + } } .assigned-to { flex-grow: 1; @@ -32,12 +55,12 @@ @extend %light; color: $gray; display: block; + margin: .2rem 0 .25rem; } .user-assigned { @extend %large; color: $primary; cursor: default; - line-height: 1.5rem; &.editable { cursor: pointer; } @@ -54,7 +77,7 @@ opacity: 0; position: absolute; right: 0; - top: 0; + top: 2rem; &:hover { color: $red; } diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index 936bbb68..ee9635ed 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -507,18 +507,23 @@ } .lb-create-edit-userstory { + .points-per-role { + flex-direction: row; + flex-wrap: wrap; + margin: 0; + } .ticket-role-points { - flex-grow: 1; - flex-shrink: 1; - max-width: calc(100% * (1/6) - .2rem); + margin: .1rem; + min-width: 20%; &:first-child { margin-left: 0; } - &:nth-child(5n+5) { + &:nth-child(4n + 4) { margin-right: 0; } - } - .points-per-role { - margin-bottom: 0; + &:last-child { + margin: .1rem 0; + min-width: 100%; + } } } diff --git a/app/styles/modules/common/nav.scss b/app/styles/modules/common/nav.scss index 6dca70cf..1227a2b2 100644 --- a/app/styles/modules/common/nav.scss +++ b/app/styles/modules/common/nav.scss @@ -49,8 +49,12 @@ tg-project-menu { } } } - svg path { - opacity: 1; + svg { + max-height: 1.5rem; + max-width: 1.5rem; + path { + opacity: 1; + } } span { display: block; diff --git a/app/styles/modules/common/ticket-data.scss b/app/styles/modules/common/ticket-data.scss index a727f403..80dbe413 100644 --- a/app/styles/modules/common/ticket-data.scss +++ b/app/styles/modules/common/ticket-data.scss @@ -1,24 +1,54 @@ -.ticket-data { +.ticket-header { + margin: 1.5rem 0 2rem; .ticket-title { @extend %larger; @extend %light; - margin: 1.5rem 0 2rem; text-transform: uppercase; - span { - margin-right: .25rem; - &:last-child { - @extend %large; - } - } + vertical-align: sub; } - .ticket-data-container { + .detail-status { @extend %small; - @extend %normal; - margin-bottom: 1rem; - .icon { + display: inline-block; + margin-left: .25rem; + position: relative; + .icon-arrow-bottom { margin-left: .25rem; } } + .detail-status-inner { + color: $white; + display: flex; + justify-content: center; + padding: .15rem .25rem; + text-transform: uppercase; + } + .pop-status { + @include popover(150px, 1.25rem, 0, '', ''); + padding: 0; + text-transform: none; + a { + @extend %text; + padding: .5rem 1rem; + } + a:hover { + background: rgba($primary-light, .2); + } + } +} + +.ticket-data-container { + @extend %small; + @extend %normal; + margin-bottom: 1rem; + .icon { + margin-left: .25rem; + } +} + +.ticket-status { + &:last-child { + margin: 0; + } .level { display: inline-block; margin-right: .5rem; @@ -29,29 +59,6 @@ float: right; text-transform: lowercase; } - - .ticket-estimation { - .ticket-role-points { - max-width: 25%; - &:first-child { - flex-basis: 100%; - max-width: 100%; - } - } - } -} - -.ticket-status { - margin-bottom: .5rem; - &:last-child { - margin: 0; - } - div { - background: darken($whitish, 5%); - padding: .5rem; - padding-right: 1rem; - transition: background .2s ease-in; - } .clickable { &:hover { background: darken($whitish, 10%); @@ -59,142 +66,153 @@ } } .type-data { + background: darken($whitish, 5%); + margin-bottom: .5rem; + padding: .5rem; + padding-right: 1rem; position: relative; + transition: background .2s ease-in; .pop-type { @include popover(150px, '', 30px, '', ''); } } .severity-data { + background: darken($whitish, 5%); + margin-bottom: .5rem; + padding: .5rem; + padding-right: 1rem; position: relative; + transition: background .2s ease-in; .pop-severity { @include popover(150px, '', 30px, '', ''); } } .priority-data { + background: darken($whitish, 5%); + margin-bottom: .5rem; + padding: .5rem; + padding-right: 1rem; position: relative; + transition: background .2s ease-in; .pop-priority { @include popover(150px, '', 30px, '', ''); } } - .status-data { - position: relative; - .pop-status { - @include popover(150px, '', 30px, '', ''); - } - } } -.ticket-track-buttons { - .track-inner { +.ticket-watch { + .ticket-watch-title { + @extend %bold; + margin-bottom: .5rem; + } + .ticket-watch-inner { + display: flex; + } + .track-icon { + position: relative; + top: 2px; + } + .ticket-watch-button, + .add-watcher { @extend %light; @extend %small; - background: darken($whitish, 5%); + background: $gray-light; + color: $white; + flex: 1; padding: .25rem; + text-align: center; text-transform: uppercase; transition: background .25s; - &:hover { - background: darken($whitish, 10%); - } - } - .track-button { - width: 100%; - } - .active { - .track-button-counter { - background: rgba($grayer, .5); + path { + fill: $white; } &:hover { - .track-inner { - background: rgba($primary-light, .2); - } + background: $primary-light; } &.is-hover { - .track-inner { - background: $red; - color: $whitish; - transition: background .3s; - } - path { + background: $red; + color: $whitish; + transition: background .3s; + svg { fill: $red-light; } } - } - .track-button-counter { - @extend %large; - background: rgba($grayer, .25); - color: $whitish; - padding: 0 .5rem; - } - .vote-button { - margin-bottom: .3rem; - } - .watch-button { - border-bottom: 0; - } - .ticket-watchers { - margin: .5rem 0; - } - .add-watcher { - display: block; - margin: .5rem; - .icon { - background: rgba($grayer, .25); - color: $whitish; - margin-right: .5rem; - padding: .25rem; - } - &:hover { - .icon { - background: $primary-light; - color: $whitish; - transition: background .3s linear; + &.active { + background: $primary-light; + &:hover { + background: $red-light; + } + svg { + fill: $white; } } + + } + .ticket-watch-button { + margin-right: .25rem; } } .ticket-detail-settings { + display: flex; + justify-content: center; margin-top: 2rem; label, - .button { - display: block; - margin-bottom: .5rem; - text-align: center; - &.editable { + .item-block, + .item-unblock, + .promote-button, + .button-delete { + background: $gray-light; + display: inline-block; + margin-right: .5rem; + padding: 1rem; + transition: background .2s linear; + transition-delay: .1s; + &:hover { + background: $gray-light; + cursor: default; + } + &.is-editable { + background: $gray-light; cursor: pointer; + &:hover { + background: $gray; + } + } + &.active { + background: $primary-light; } +input { display: none; } } - .loading-spinner { - @extend %loading-spinner; + .item-block, + .item-unblock { + display: none; + &.is-active { + display: inline-block; + } } - .button-gray { - background: $gray-light; + .item-unblock { + background: $red; + } + .button-delete { + background: $red-light; &:hover { - background: $gray-light; - } - &.editable { - &:hover { - background: $grayer; - cursor: pointer; - } - } - &.active { - background: $primary; + background: $red; + cursor: pointer; } } - .item-block { - &.editable { - &:hover { - background: $red; - cursor: pointer; - } - } + img { + max-height: 1.25rem; + max-width: 1.25rem; + width: 100%; } - .button-red { - display: block; - margin-top: 2rem; + svg { + fill: $white; + height: 100%; + max-height: 1.25rem; + max-width: 1.25rem; + width: 100%; } } diff --git a/app/svg/client-requirement.svg b/app/svg/client-requirement.svg new file mode 100644 index 00000000..fd20989a --- /dev/null +++ b/app/svg/client-requirement.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/svg/iocaine.svg b/app/svg/iocaine.svg new file mode 100644 index 00000000..868c76d0 --- /dev/null +++ b/app/svg/iocaine.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/svg/lock.svg b/app/svg/lock.svg index b2ee1e5a..d39b2ba0 100644 --- a/app/svg/lock.svg +++ b/app/svg/lock.svg @@ -1,7 +1,3 @@ - - - - - - + + diff --git a/app/svg/project.svg b/app/svg/project.svg new file mode 100644 index 00000000..6e3ce332 --- /dev/null +++ b/app/svg/project.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/svg/promote.svg b/app/svg/promote.svg new file mode 100644 index 00000000..329e718f --- /dev/null +++ b/app/svg/promote.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/svg/team-requirement.svg b/app/svg/team-requirement.svg new file mode 100644 index 00000000..154ea48c --- /dev/null +++ b/app/svg/team-requirement.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/svg/trash.svg b/app/svg/trash.svg new file mode 100644 index 00000000..281f1d29 --- /dev/null +++ b/app/svg/trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/svg/unlock.svg b/app/svg/unlock.svg new file mode 100644 index 00000000..fe3188a5 --- /dev/null +++ b/app/svg/unlock.svg @@ -0,0 +1,3 @@ + + +