Refactor sidebar

stable
Xavier Julián 2015-11-19 16:37:36 +01:00 committed by David Barragán Merino
parent 206e64cd26
commit f63b362054
56 changed files with 683 additions and 444 deletions

View File

@ -98,16 +98,26 @@ module.factory("$selectedText", ["$window", "$document", SelectedText])
CheckPermissionDirective = (projectService) -> CheckPermissionDirective = (projectService) ->
render = ($el, project, permission) -> render = ($el, project, permission) ->
if project && permission
$el.removeClass('hidden') if project.get('my_permissions').indexOf(permission) > -1 $el.removeClass('hidden') if project.get('my_permissions').indexOf(permission) > -1
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
$el.addClass('hidden') $el.addClass('hidden')
permission = $attrs.tgCheckPermission permission = $attrs.tgCheckPermission
$scope.$watch ( () -> unwatch = $scope.$watch () ->
return projectService.project 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", -> $scope.$on "$destroy", ->
$el.off() $el.off()

View File

@ -185,13 +185,13 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
promise = $repo.save($model.$modelValue) promise = $repo.save($model.$modelValue)
promise.then -> promise.then ->
$confirm.notify("success")
watchers = _.map(watchers, (watcherId) -> $scope.usersById[watcherId]) watchers = _.map(watchers, (watcherId) -> $scope.usersById[watcherId])
renderWatchers(watchers) renderWatchers(watchers)
$rootscope.$broadcast("object:updated") $rootscope.$broadcast("object:updated")
promise.then null, -> promise.then null, ->
$model.$modelValue.revert() $model.$modelValue.revert()
$confirm.notify("error")
deleteWatcher = $qqueue.bindAdd (watcherIds) => deleteWatcher = $qqueue.bindAdd (watcherIds) =>
item = $model.$modelValue.clone() item = $model.$modelValue.clone()
@ -200,7 +200,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
promise = $repo.save($model.$modelValue) promise = $repo.save($model.$modelValue)
promise.then -> promise.then ->
$confirm.notify("success")
watchers = _.map(item.watchers, (watcherId) -> $scope.usersById[watcherId]) watchers = _.map(item.watchers, (watcherId) -> $scope.usersById[watcherId])
renderWatchers(watchers) renderWatchers(watchers)
$rootscope.$broadcast("object:updated") $rootscope.$broadcast("object:updated")
@ -208,7 +207,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
item.revert() item.revert()
$confirm.notify("error") $confirm.notify("error")
renderWatchers = (watchers) -> renderWatchers = (watchers) ->
ctx = { ctx = {
watchers: watchers watchers: watchers
@ -235,12 +233,6 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
deleteWatcher(watcherIds) 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) -> $scope.$on "watcher:added", (ctx, watcherId) ->
watchers = _.clone($model.$modelValue.watchers, false) watchers = _.clone($model.$modelValue.watchers, false)
watchers.push(watcherId) watchers.push(watcherId)
@ -285,7 +277,6 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template
promise = $repo.save($model.$modelValue) promise = $repo.save($model.$modelValue)
promise.then -> promise.then ->
currentLoading.finish() currentLoading.finish()
$confirm.notify("success")
renderAssignedTo($model.$modelValue) renderAssignedTo($model.$modelValue)
$rootscope.$broadcast("object:updated") $rootscope.$broadcast("object:updated")
promise.then null, -> promise.then null, ->
@ -295,13 +286,21 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template
return promise return promise
renderAssignedTo = (issue) -> renderAssignedTo = (assignedObject) ->
assignedToId = issue?.assigned_to if assignedObject?.assigned_to_extra_info?
assignedTo = if assignedToId? then $scope.usersById[assignedToId] else null 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 = { ctx = {
assignedTo: assignedTo assignedTo: assignedTo
isEditable: isEditable() isEditable: isEditable()
isIocaine: isIocaine
} }
html = $compile(template(ctx))($scope) html = $compile(template(ctx))($scope)
$el.html(html) $el.html(html)
@ -357,14 +356,14 @@ BlockButtonDirective = ($rootscope, $loading, $template) ->
return if not item return if not item
if isEditable() if isEditable()
$el.find('.item-block').addClass('editable') $el.find('.item-block').addClass('is-editable')
if item.is_blocked if item.is_blocked
$el.find('.item-block').hide() $el.find('.item-block').removeClass('is-active')
$el.find('.item-unblock').show() $el.find('.item-unblock').addClass('is-active')
else else
$el.find('.item-block').show() $el.find('.item-block').addClass('is-active')
$el.find('.item-unblock').hide() $el.find('.item-unblock').removeClass('is-active')
$el.on "click", ".item-block", (event) -> $el.on "click", ".item-block", (event) ->
event.preventDefault() event.preventDefault()
@ -711,13 +710,16 @@ ListItemTaskStatusDirective = ->
module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective) module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective)
ListItemAssignedtoDirective = ($template) -> ListItemAssignedtoDirective = ($template, $translate) ->
template = $template.get("common/components/list-item-assigned-to-avatar.html", true) template = $template.get("common/components/list-item-assigned-to-avatar.html", true)
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
bindOnce $scope, "usersById", (usersById) -> bindOnce $scope, "usersById", (usersById) ->
item = $scope.$eval($attrs.tgListitemAssignedto) 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] member = usersById[item.assigned_to]
if member if member
@ -728,7 +730,7 @@ ListItemAssignedtoDirective = ($template) ->
return {link:link} return {link:link}
module.directive("tgListitemAssignedto", ["$tgTemplate", ListItemAssignedtoDirective]) module.directive("tgListitemAssignedto", ["$tgTemplate", "$translate", ListItemAssignedtoDirective])
ListItemIssueStatusDirective = -> ListItemIssueStatusDirective = ->

View File

@ -31,7 +31,7 @@ module = angular.module("taigaCommon")
## User story estimation directive (for Lightboxes) ## 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. # Display the points of a US and you can edit it.
# #
# Example: # Example:
@ -72,14 +72,15 @@ LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $
require: "ngModel" 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 ## 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. # Display the points of a US and you can edit it.
# #
# Example: # Example:
@ -120,8 +121,8 @@ UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qq
require: "ngModel" require: "ngModel"
} }
module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", "$tgTemplate", "$compile" module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgQqueue",
UsEstimationDirective]) "$tgTemplate", "$compile", UsEstimationDirective])
############################################################################# #############################################################################
@ -145,7 +146,6 @@ EstimationsService = ($template, $qqueue, $repo, $confirm, $q) ->
$qqueue.add () => $qqueue.add () =>
onSuccess = => onSuccess = =>
deferred.resolve() deferred.resolve()
$confirm.notify("success")
onError = => onError = =>
$confirm.notify("error") $confirm.notify("error")
@ -247,4 +247,5 @@ EstimationsService = ($template, $qqueue, $repo, $confirm, $q) ->
create: create create: create
} }
module.factory("$tgEstimationsService", ["$tgTemplate", "$tgQqueue", "$tgRepo", "$tgConfirm", "$q", EstimationsService]) module.factory("$tgEstimationsService", ["$tgTemplate", "$tgQqueue", "$tgRepo", "$tgConfirm",
"$q", EstimationsService])

View File

@ -282,11 +282,10 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t
issue.status = statusId issue.status = statusId
currentLoading = $loading() currentLoading = $loading()
.target($el.find(".level-name")) .target($el)
.start() .start()
onSuccess = -> onSuccess = ->
$confirm.notify("success")
$model.$setViewValue(issue) $model.$setViewValue(issue)
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()
@ -299,7 +298,7 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t
$repo.save(issue).then(onSuccess, onError) $repo.save(issue).then(onSuccess, onError)
$el.on "click", ".status-data", (event) -> $el.on "click", ".js-edit-status", (event) ->
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
return if not isEditable() return if not isEditable()
@ -373,7 +372,6 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $tem
.start() .start()
onSuccess = -> onSuccess = ->
$confirm.notify("success")
$model.$setViewValue(issue) $model.$setViewValue(issue)
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()
@ -462,7 +460,6 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue,
.start() .start()
onSuccess = -> onSuccess = ->
$confirm.notify("success")
$model.$setViewValue(issue) $model.$setViewValue(issue)
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()
@ -551,7 +548,6 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue,
.start() .start()
onSuccess = -> onSuccess = ->
$confirm.notify("success")
$model.$setViewValue(issue) $model.$setViewValue(issue)
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()

View File

@ -778,7 +778,7 @@ module.directive("tgIssueStatusInlineEdition", ["$tgRepo", "$tgTemplate", "$root
## Issue assigned to Directive ## Issue assigned to Directive
############################################################################# #############################################################################
IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) ->
template = _.template(""" template = _.template("""
<img src="<%- imgurl %>" alt="<%- name %>"/> <img src="<%- imgurl %>" alt="<%- name %>"/>
<figcaption><%- name %></figcaption> <figcaption><%- name %></figcaption>
@ -786,11 +786,15 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) ->
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
updateIssue = (issue) -> updateIssue = (issue) ->
ctx = {name: "Unassigned", imgurl: "/" + window._version + "/images/unnamed.png"} ctx = {
member = $scope.usersById[issue.assigned_to] name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"),
imgurl: "/#{window._version}/images/unnamed.png"
}
member = issue.assigned_to_extra_info
if member if member
ctx.imgurl = member.photo
ctx.name = member.full_name_display ctx.name = member.full_name_display
ctx.imgurl = member.photo
$el.find(".avatar").html(template(ctx)) $el.find(".avatar").html(template(ctx))
$el.find(".issue-assignedto").attr('title', ctx.name) $el.find(".issue-assignedto").attr('title', ctx.name)
@ -822,5 +826,5 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) ->
return {link: link} return {link: link}
module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate"
IssueAssignedToInlineEditionDirective]) IssueAssignedToInlineEditionDirective])

View File

@ -527,7 +527,7 @@ module.directive("tgKanbanWipLimit", KanbanWipLimitDirective)
## Kanban User Directive ## Kanban User Directive
############################################################################# #############################################################################
KanbanUserDirective = ($log, $compile) -> KanbanUserDirective = ($log, $compile, $translate) ->
template = _.template(""" template = _.template("""
<figure class="avatar"> <figure class="avatar">
<a href="#" title="{{'US.ASSIGN' | translate}}" <% if (!clickable) {%>class="not-clickable"<% } %>> <a href="#" title="{{'US.ASSIGN' | translate}}" <% if (!clickable) {%>class="not-clickable"<% } %>>
@ -555,9 +555,17 @@ KanbanUserDirective = ($log, $compile) ->
render = (user) -> render = (user) ->
if user is undefined 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 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) html = $compile(template(ctx))($scope)
$el.html(html) $el.html(html)
@ -588,4 +596,4 @@ KanbanUserDirective = ($log, $compile) ->
return {link: link, require:"ngModel"} return {link: link, require:"ngModel"}
module.directive("tgKanbanUserAvatar", ["$log", "$compile", KanbanUserDirective]) module.directive("tgKanbanUserAvatar", ["$log", "$compile", "$translate", KanbanUserDirective])

View File

@ -241,7 +241,7 @@ RelatedTasksDirective = ($repo, $rs, $rootscope) ->
return {link: link} return {link: link}
module.directive("tgRelatedTasks", ["$tgRepo", "$tgResources", "$rootScope", RelatedTasksDirective]) module.directive("tgRelatedTasks", ["$tgRepo", "$tgResources", "$rootScope", RelatedTasksDirective])
RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) ->
template = _.template(""" template = _.template("""
<img src="<%- imgurl %>" alt="<%- name %>"/> <img src="<%- imgurl %>" alt="<%- name %>"/>
<figcaption><%- name %></figcaption> <figcaption><%- name %></figcaption>
@ -249,7 +249,10 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
updateRelatedTask = (task) -> 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] member = $scope.usersById[task.assigned_to]
if member if member
ctx.imgurl = member.photo ctx.imgurl = member.photo
@ -287,4 +290,5 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService
return {link: link} return {link: link}
module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", RelatedTaskAssignedToInlineEditionDirective]) module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate",
RelatedTaskAssignedToInlineEditionDirective])

View File

@ -436,7 +436,7 @@ module.directive("tgTaskboardSquishColumn", ["$tgResources", TaskboardSquishColu
## Taskboard User Directive ## Taskboard User Directive
############################################################################# #############################################################################
TaskboardUserDirective = ($log) -> TaskboardUserDirective = ($log, $translate) ->
clickable = false clickable = false
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
@ -447,9 +447,17 @@ TaskboardUserDirective = ($log) ->
user = $scope.usersById[assigned_to] user = $scope.usersById[assigned_to]
if user is undefined 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 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) username_label.text($scope.name)
@ -484,4 +492,4 @@ TaskboardUserDirective = ($log) ->
} }
module.directive("tgTaskboardUserAvatar", ["$log", TaskboardUserDirective]) module.directive("tgTaskboardUserAvatar", ["$log", "$translate", TaskboardUserDirective])

View File

@ -278,12 +278,11 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $co
task.status = status task.status = status
currentLoading = $loading() currentLoading = $loading()
.target($el.find(".level-name")) .target($el)
.start() .start()
onSuccess = -> onSuccess = ->
$model.$setViewValue(task) $model.$setViewValue(task)
$confirm.notify("success")
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()
@ -293,7 +292,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $co
$repo.save(task).then(onSuccess, onError) $repo.save(task).then(onSuccess, onError)
$el.on "click", ".status-data", (event) -> $el.on "click", ".js-edit-status", (event) ->
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
return if not isEditable() return if not isEditable()
@ -327,17 +326,8 @@ module.directive("tgTaskStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "
"$compile", "$translate", "$tgTemplate", TaskStatusButtonDirective]) "$compile", "$translate", "$tgTemplate", TaskStatusButtonDirective])
TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $compile) -> TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $compile, $template) ->
template = _.template(""" template = $template.get("issue/iocaine-button.html", true)
<fieldset title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}">
<label for="is-iocaine"
translate="TASK.ACTION_IOCAINE"
class="button button-gray is-iocaine <% if(isEditable){ %>editable<% }; %> <% if(isIocaine){ %>active<% }; %>">
Iocaine
</label>
<input type="checkbox" id="is-iocaine" name="is-iocaine"/>
</fieldset>
""")
link = ($scope, $el, $attrs, $model) -> link = ($scope, $el, $attrs, $model) ->
isEditable = -> isEditable = ->
@ -367,7 +357,6 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue
promise.then -> promise.then ->
$model.$setViewValue(task) $model.$setViewValue(task)
$confirm.notify("success")
$rootscope.$broadcast("object:updated") $rootscope.$broadcast("object:updated")
promise.then null, -> promise.then null, ->
@ -395,4 +384,4 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue
} }
module.directive("tgTaskIsIocaineButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", module.directive("tgTaskIsIocaineButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue",
"$compile", TaskIsIocaineButtonDirective]) "$compile", "$tgTemplate", TaskIsIocaineButtonDirective])

View File

@ -277,54 +277,6 @@ UsStatusDisplayDirective = ($template, $compile) ->
module.directive("tgUsStatusDisplay", ["$tgTemplate", "$compile", UsStatusDisplayDirective]) 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 ## User story status button directive
############################################################################# #############################################################################
@ -365,11 +317,10 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp
$.fn.popover().closeAll() $.fn.popover().closeAll()
currentLoading = $loading() currentLoading = $loading()
.target($el.find(".level-name")) .target($el)
.start() .start()
onSuccess = -> onSuccess = ->
$confirm.notify("success")
$model.$setViewValue(us) $model.$setViewValue(us)
$rootScope.$broadcast("object:updated") $rootScope.$broadcast("object:updated")
currentLoading.finish() currentLoading.finish()
@ -380,7 +331,7 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp
$repo.save(us).then(onSuccess, onError) $repo.save(us).then(onSuccess, onError)
$el.on "click", ".status-data", (event) -> $el.on "click", ".js-edit-status", (event) ->
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
return if not isEditable() return if not isEditable()
@ -425,10 +376,6 @@ UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qq
return $scope.project.my_permissions.indexOf("modify_us") != -1 return $scope.project.my_permissions.indexOf("modify_us") != -1
render = (us) -> render = (us) ->
if not canEdit() and not us.team_requirement
$el.html("")
return
ctx = { ctx = {
canEdit: canEdit() canEdit: canEdit()
isRequired: us.team_requirement isRequired: us.team_requirement
@ -489,10 +436,6 @@ UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $
return $scope.project.my_permissions.indexOf("modify_us") != -1 return $scope.project.my_permissions.indexOf("modify_us") != -1
render = (us) -> render = (us) ->
if not canEdit() and not us.client_requirement
$el.html("")
return
ctx = { ctx = {
canEdit: canEdit() canEdit: canEdit()
isRequired: us.client_requirement isRequired: us.client_requirement

View File

@ -24,6 +24,8 @@
"FROM": "from", "FROM": "from",
"TO": "to", "TO": "to",
"CLOSE": "close", "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_NOTE": "Why is this user story blocked?",
"BLOCKED_REASON": "Please explain the reason", "BLOCKED_REASON": "Please explain the reason",
"GO_HOME": "Take me home", "GO_HOME": "Take me home",
@ -36,6 +38,8 @@
"EXTERNAL_USER": "an external user", "EXTERNAL_USER": "an external user",
"GENERIC_ERROR": "One of our Oompa Loompas says {{error}}.", "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!", "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.", "CAPSLOCK_WARNING": "Be careful! You're writing with capital letters and this input is case sensitive.",
"FORM_ERRORS": { "FORM_ERRORS": {
"DEFAULT_MESSAGE": "This value seems to be invalid.", "DEFAULT_MESSAGE": "This value seems to be invalid.",
@ -150,6 +154,7 @@
"OPEN": "Open" "OPEN": "Open"
}, },
"WATCHERS": { "WATCHERS": {
"WATCHERS": "Watchers",
"ADD": "Add watchers", "ADD": "Add watchers",
"TITLE_ADD": "Add a project member to the watchers list", "TITLE_ADD": "Add a project member to the watchers list",
"DELETE": "Delete watcher", "DELETE": "Delete watcher",

View File

@ -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}}

View File

@ -20,9 +20,10 @@
class WatchButtonController class WatchButtonController
@.$inject = [ @.$inject = [
"tgCurrentUserService", "tgCurrentUserService",
"$rootScope"
] ]
constructor: (@currentUserService) -> constructor: (@currentUserService, @rootScope) ->
@.user = @currentUserService.getUser() @.user = @currentUserService.getUser()
@.isMouseOver = false @.isMouseOver = false
@.loading = false @.loading = false
@ -33,6 +34,22 @@ class WatchButtonController
showTextWhenMouseIsLeave: -> showTextWhenMouseIsLeave: ->
@.isMouseOver = false @.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: -> toggleWatch: ->
@.loading = true @.loading = true

View File

@ -100,3 +100,24 @@ describe "WatchButton", ->
expect(ctrl.loading).to.be.false; expect(ctrl.loading).to.be.false;
done() 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')

View File

@ -27,7 +27,8 @@ WatchButtonDirective = ->
onUnwatch: "=" onUnwatch: "="
} }
controllerAs: "vm", 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) angular.module("taigaComponents").directive("tgWatchButton", WatchButtonDirective)

View File

@ -32,7 +32,9 @@ $dropdown-width: 350px;
} }
svg { svg {
height: 1.6rem; height: 1.6rem;
max-height: 1.6rem;
max-width: 2rem; max-width: 2rem;
width: 1.6rem;
} }
path { path {
fill: $white; fill: $white;
@ -79,7 +81,9 @@ $dropdown-width: 350px;
} }
svg { svg {
height: 1.2rem; height: 1.2rem;
max-height: 1.2rem;
max-width: 1.2rem; max-width: 1.2rem;
width: 1.2rem;
path { path {
fill: $top-icon-color; fill: $top-icon-color;
transition: all .2s; transition: all .2s;

View File

@ -1,6 +1,10 @@
<% if (assignedTo) { %> <% if (assignedTo) { %>
.user-avatar .user-avatar(class!="<% if(isIocaine){ %> is-iocaine <% }; %>")
img(src!="<%- assignedTo.photo %>", alt!="<%- assignedTo.full_name_display %>") 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 .assigned-to
@ -9,11 +13,7 @@
a(href="" title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}", a(href="" title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}",
class!="user-assigned <% if(isEditable){ %>editable<% }; %>") class!="user-assigned <% if(isEditable){ %>editable<% }; %>")
span.assigned-name span.assigned-name
<% if (assignedTo) { %>
<%- assignedTo.full_name_display %> <%- assignedTo.full_name_display %>
<% } else { %>
| {{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }}
<% } %>
<% if(isEditable){ %> <% if(isEditable){ %>
span.icon.icon-arrow-bottom span.icon.icon-arrow-bottom
<% }; %> <% }; %>

View File

@ -1,4 +1,10 @@
a(href="#", class="button button-gray item-block") a.button-gray.item-block(
span(translate="COMMON.BLOCK") href=""
a(href="#", class="button button-red item-unblock") title="{{ 'COMMON.BLOCK' | translate }}"
span(translate="COMMON.UNBLOCK") )
include ../../../svg/lock.svg
a.button-red.item-unblock(
href=""
title="{{ 'COMMON.UNBLOCK' | translate }}"
)
include ../../../svg/unlock.svg

View File

@ -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 .created-by
a(href="{{url}}", title="{{owner.full_name_display}}") a.created-title(
span.created-title(translate="COMMON.CREATED_BY", translate-values="{ 'fullDisplayName': owner.full_name_display}") href="{{url}}"
span.created-date title="{{owner.full_name_display}}"
| {{date}} 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}}"
)

View File

@ -1,2 +1,5 @@
a.button-red.button-delete(href="") a.button-red.button-delete(
span(translate="COMMON.DELETE") href=""
title="{{ 'COMMON.DELETE' | translate }}"
)
include ../../../svg/trash.svg

View File

@ -3,5 +3,3 @@ span(translate="COMMON.STATUS.CLOSED")
<% } else { %> <% } else { %>
span(translate="COMMON.STATUS.OPEN") span(translate="COMMON.STATUS.OPEN")
<% } %> <% } %>
span(class="detail-status", style!="color:<%- status.color %>")
| <%- status.name %>

View File

@ -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")
<% }; %>

View File

@ -1,9 +1,12 @@
ul.points-per-role 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 li.ticket-role-points.total
span.points <%- totalPoints %> span.points <%- totalPoints %>
span.role(translate="US.TOTAL_POINTS") 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 %>
<% }); %>

View File

@ -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"
)

View File

@ -57,8 +57,9 @@ div.wrapper(
tg-bo-href="nextUrl" tg-bo-href="nextUrl"
title="{{'ISSUES.TITLE_NEXT_ISSUE' | translate}}" title="{{'ISSUES.TITLE_NEXT_ISSUE' | translate}}"
) )
.subheader
div.tags-block(tg-tag-line, ng-model="issue", required-perm="modify_issue") 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") 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") tg-history(ng-model="issue", type="issue")
sidebar.menu-secondary.sidebar.ticket-data sidebar.menu-secondary.sidebar.ticket-data
section.status
.ticket-title(tg-issue-status-display, ng-model="issue") .ticket-header
tg-created-by-display.ticket-created-by(ng-model="issue") 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-data-container
div.ticket-status(tg-issue-type-button, ng-model="issue") 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-severity-button, ng-model="issue")
div.ticket-status(tg-issue-priority-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.ticket-assigned-to(tg-assigned-to, ng-model="issue", required-perm="modify_issue")
section.track-buttons-container.ticket-track-buttons section.ticket-watch-buttons
div.ticket-watch(
div.watch-button tg-watch-button
tg-watch-button(
item="issue" item="issue"
data-environment="ticket"
on-watch="ctrl.onWatch" on-watch="ctrl.onWatch"
on-unwatch="ctrl.onUnwatch" on-unwatch="ctrl.onUnwatch"
) )
div.ticket-watchers( div.ticket-watchers(
tg-watchers tg-watchers
ng-model="issue" ng-model="issue"
required-perm="modify_issue" required-perm="modify_us"
) )
section.ticket-detail-settings section.ticket-detail-settings
tg-promote-issue-to-us-button(tg-check-permission="add_us", ng-model="issue") tg-promote-issue-to-us-button(
tg-block-button(tg-check-permission="modify_issue", ng-model="issue") tg-check-permission="add_us",
ng-model="issue"
)
tg-block-button(
tg-check-permission="modify_issue",
ng-model="issue"
)
tg-delete-button( tg-delete-button(
tg-check-permission="delete_issue", tg-check-permission="delete_issue",
on-delete-title="{{'ISSUES.ACTION_DELETE' | translate}}", on-delete-title="{{'ISSUES.ACTION_DELETE' | translate}}",

View File

@ -1,15 +1,20 @@
div(class!="status-data <% if(editable){ %>clickable<% }%>") span.detail-status-inner.js-edit-status(
span(class="level", style!="background-color:<%- status.color %>") class!="<% if(editable){ %>clickable<% }%>"
span(class="status-status") <%- status.name %> style!="background-color:<%- status.color %>"
ng-click="editStatus()"
)
span <%- status.name %>
<% if(editable){ %> <% if(editable){ %>
span(class="icon icon-arrow-bottom") span.icon.icon-arrow-bottom
<% } %> <% }%>
span(class="level-name", translate="COMMON.FIELDS.STATUS")
ul(class="popover pop-status") ul.pop-status
<% _.each(statuses, function(st) { %> <% _.each(statuses, function(st) { %>
li li
a(href="", class="status", title!="<%- st.name %>", a.status(
data-status-id!="<%- st.id %>") href=""
title!="<%- st.name %>"
data-status-id!="<%- st.id %>"
)
| <%- st.name %> | <%- st.name %>
<% }); %> <% }); %>

View File

@ -1,2 +1,2 @@
a(class="button button-gray editable", tg-check-permission="add_us") a.promote-button.is-editable(tg-check-permission="add_us")
span(translate="ISSUES.ACTION_PROMOTE_TO_US") include ../../svg/promote.svg

View File

@ -72,8 +72,9 @@ div.wrapper(
tg-bo-href="nextUrl" tg-bo-href="nextUrl"
title="{{'TASK.NEXT' | translate}}" title="{{'TASK.NEXT' | translate}}"
) )
.subheader
div.tags-block(tg-tag-line, ng-model="task", required-perm="modify_task") 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") 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 sidebar.menu-secondary.sidebar.ticket-data
section.status .ticket-header
span.ticket-title(
.ticket-title(tg-task-status-display, ng-model="task") tg-task-status-display
ng-model="task"
.ticket-created-by(tg-created-by-display, ng-model="task") )
span.detail-status(
.ticket-data-container tg-task-status-button
.ticket-status(tg-task-status-button, ng-model="task") ng-model="task"
)
section.ticket-assigned-to(tg-assigned-to, ng-model="task", required-perm="modify_task") section.ticket-assigned-to(tg-assigned-to, ng-model="task", required-perm="modify_task")
section.track-buttons-container.ticket-track-buttons section.ticket-watch-buttons
div.watch-button div.ticket-watch(
tg-watch-button( tg-watch-button
item="task" item="task"
data-environment="ticket"
on-watch="ctrl.onWatch" on-watch="ctrl.onWatch"
on-unwatch="ctrl.onUnwatch" on-unwatch="ctrl.onUnwatch"
) )
div.ticket-watchers( div.ticket-watchers(
tg-watchers, tg-watchers
ng-model="task", ng-model="task"
required-perm="modify_task" required-perm="modify_us"
) )
section.ticket-detail-settings section.ticket-detail-settings

View File

@ -1,4 +1,11 @@
label(for="client-requirement", label.button-gray.client-requirement(
class!="button button-gray client-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>", translate="US.FIELDS.CLIENT_REQUIREMENT") for="client-requirement"
class!="<% if(canEdit){ %>is-editable<% }; %> <% if(isRequired){ %>active<% }; %>"
input(type="checkbox", id="client-requirement", name="client-requirement") title="{{ 'COMMON.CLIENT_REQUIREMENT' | translate }}"
)
include ../../svg/client-requirement.svg
input(
type="checkbox"
id="client-requirement"
name="client-requirement"
)

View File

@ -65,8 +65,9 @@ div.wrapper(
tg-bo-href="nextUrl" tg-bo-href="nextUrl"
title="{{'US.NEXT' | translate}}" title="{{'US.NEXT' | translate}}"
) )
.subheader
div.tags-block(tg-tag-line, ng-model="us", required-perm="modify_us") .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") 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 sidebar.menu-secondary.sidebar.ticket-data
section
div.ticket-title( section.ticket-header
span.ticket-title(
tg-us-status-display tg-us-status-display
ng-model="us" ng-model="us"
) )
span.detail-status(
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 tg-us-status-button
ng-model="us" ng-model="us"
) )
section.ticket-estimation tg-us-estimation.ticket-estimation(ng-model="us")
tg-us-estimation(ng-model="us")
section.ticket-assigned-to( section.ticket-assigned-to(
tg-assigned-to tg-assigned-to
@ -117,20 +112,21 @@ div.wrapper(
required-perm="modify_us" required-perm="modify_us"
) )
section.track-buttons-container.ticket-track-buttons section.ticket-watch-buttons
div.watch-button div.ticket-watch(
tg-watch-button( tg-watch-button
item="us" item="us"
data-environment="ticket"
on-watch="ctrl.onWatch" on-watch="ctrl.onWatch"
on-unwatch="ctrl.onUnwatch" on-unwatch="ctrl.onUnwatch"
) )
div.ticket-watchers( div.ticket-watchers(
tg-watchers tg-watchers
ng-model="us" ng-model="us"
required-perm="modify_us" required-perm="modify_us"
) )
section.ticket-detail-settings section.ticket-detail-settings
tg-us-team-requirement-button(ng-model="us") tg-us-team-requirement-button(ng-model="us")
tg-us-client-requirement-button(ng-model="us") tg-us-client-requirement-button(ng-model="us")

View File

@ -1,14 +1,19 @@
div(class!="status-data <% if(editable){ %>clickable<% }%>") span.detail-status-inner.js-edit-status(
span.level(style!="background-color:<%- status.color %>") class!="<% if(editable){ %>clickable<% }%>"
span.status-status <%- status.name %> style!="background-color:<%- status.color %>"
)
span <%- status.name %>
<% if(editable){ %> <% if(editable){ %>
span.icon.icon-arrow-bottom span.icon.icon-arrow-bottom
<% }%> <% }%>
span.level-name(translate="COMMON.FIELDS.STATUS")
ul.popover.pop-status ul.pop-status.popover
<% _.each(statuses, function(st) { %> <% _.each(statuses, function(st) { %>
li 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 %> | <%- st.name %>
<% }); %> <% }); %>

View File

@ -1,2 +0,0 @@
.current-progress(ng-style='style')
div.tasks-completed(translate="US.TASK_COMPLETED", translate-values='{ totalTasks: totalTasks, totalClosedTasks: totalClosedTasks}')

View File

@ -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") input(
type="checkbox"
id="team-requirement"
name="team-requirement"
)

View File

@ -1,29 +1,45 @@
.ticket-created-by { .ticket-created-by {
display: flex; display: flex;
margin-bottom: 1rem; justify-content: flex-end;
margin-top: .5rem; @include breakpoint(laptop) {
position: relative; justify-content: flex-start;
margin-bottom: .5rem;
}
.user-avatar { .user-avatar {
flex-basis: 3rem; flex-basis: 2rem;
flex-grow: 0; flex-grow: 0;
margin-left: .5rem;
@include breakpoint(laptop) {
margin-left: 0;
margin-right: .5rem; margin-right: .5rem;
order: 1;
}
img { img {
width: 100%; width: 100%;
} }
} }
.created-by { .created-by {
@include breakpoint(laptop) {
order: 2;
}
.created-title, .created-title,
.created-date { .created-date {
@extend %light; @extend %light;
@extend %small; @extend %small;
color: $gray; color: $gray;
display: block; display: block;
line-height: 1.5; text-align: right;
@include breakpoint(laptop) {
text-align: left;
}
} }
.created-title { .created-title {
color: $primary; color: $primary;
&.editable { }
cursor: pointer; .created-date {
margin-left: .5rem;
@include breakpoint(laptop) {
margin-left: 0;
} }
} }
} }

View File

@ -1,48 +1,56 @@
%estimation { @mixin estimation {
.points-per-role { .points-per-role {
display: flex; display: flex;
flex-wrap: wrap; flex-direction: column;
justify-content: center;
} }
.ticket-role-points { .ticket-role-points {
background: rgba($gray-light, .1); background: rgba($gray-light, .2);
border-radius: 2px; color: $gray-light;
color: rgba($grayer, .3); display: flex;
flex-basis: 20%; flex: 1;
flex-grow: 1; justify-content: space-between;
flex-shrink: 0; margin-bottom: .1rem;
margin: .1rem; padding: .5rem 1rem;
padding: .5rem 0 .1rem;
position: relative; position: relative;
text-align: center;
transition: color .3s linear; transition: color .3s linear;
&.clickable {
&:hover,
&.active { &.active {
background: rgba($primary-light, .9); background: rgba($primary-light, .9);
color: $whitish; color: $whitish;
} .points,
&:first-child { .role,
background: rgba($grayer, .25); .icon-arrow-bottom {
border-radius: 0;
color: $whitish; color: $whitish;
} }
}
}
&:last-child { &: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 { .points {
@extend %larger; @extend %light;
@extend %text; color: $grayer;
display: block;
text-align: center;
} }
.role { .role {
@extend %small; @extend %light;
@include ellipsis(90%);
display: inline-block;
text-align: center;
} }
} }
.popover { .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 { li {
display: inline-block; display: inline-block;
width: 23%; width: 23%;
@ -57,11 +65,11 @@
} }
} }
&.fix { &.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 { .ticket-estimation {
@extend %estimation; @include estimation;
} }

View File

@ -63,6 +63,8 @@ $summary-background: $grayer;
svg { svg {
fill: $black; fill: $black;
height: 100%; height: 100%;
max-height: 2rem;
max-width: 2rem;
transition: all .2s; transition: all .2s;
width: 100%; width: 100%;
} }

View File

@ -38,8 +38,9 @@
display: inline-block; display: inline-block;
} }
input { input {
margin-right: .25rem;
padding: .4rem; padding: .4rem;
width: 14rem; width: 10rem;
} }
.tag { .tag {
@extend %small; @extend %small;

View File

@ -1,11 +1,11 @@
%user-list { @mixin user-list {
.user-list-single { .user-list-single {
align-content: center; align-content: center;
align-items: center; align-items: center;
background: transparent; background: transparent;
border-bottom: 1px solid $whitish; border-bottom: 1px solid $whitish;
display: flex; display: flex;
padding: .5rem .5rem .3rem; padding: .25rem 0;
vertical-align: middle; vertical-align: middle;
&:last-child { &:last-child {
@ -28,7 +28,7 @@
} }
.assigned-to-list { .assigned-to-list {
@extend %user-list; @include user-list;
margin-top: 1rem; margin-top: 1rem;
.user-list-single { .user-list-single {
&:hover, &:hover,
@ -59,7 +59,7 @@
} }
.ticket-watchers { .ticket-watchers {
@extend %user-list; @include user-list;
margin-top: 1rem; margin-top: 1rem;
.user-list-single { .user-list-single {
&:hover { &:hover {

View File

@ -47,6 +47,11 @@ sup {
cursor: move; cursor: move;
} }
svg {
max-height: 1rem;
max-width: 1rem;
}
//Datepicker //Datepicker
.pika-single { .pika-single {
// scss-lint:disable ImportantRule // scss-lint:disable ImportantRule

View File

@ -133,8 +133,8 @@
} }
.icon { .icon {
svg { svg {
max-height: 1rem; height: 1rem;
max-width: 1rem; width: 1rem;
} }
path { path {
fill: currentcolor; fill: currentcolor;

View File

@ -18,6 +18,10 @@
padding: 0 33%; padding: 0 33%;
text-align: center; text-align: center;
width: 100%; width: 100%;
svg {
max-height: 100%;
max-width: 100%;
}
} }
.logo { .logo {
@extend %xxlarge; @extend %xxlarge;

View File

@ -1,5 +1,5 @@
.us-story-main-data { .us-story-main-data {
margin-bottom: 2rem; margin-bottom: 1rem;
header { header {
align-content: center; align-content: center;
align-items: stretch; 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 { .duty-content {
@include cursor-progress; @include cursor-progress;
position: relative; position: relative;

View File

@ -17,6 +17,8 @@
} }
svg { svg {
height: 1.4rem; height: 1.4rem;
max-height: 1.4rem;
max-width: 1.5rem;
width: 1.5rem; width: 1.5rem;
} }
path { path {

View File

@ -1,7 +1,10 @@
.ticket-assigned-to { .ticket-assigned-to {
align-items: center; align-items: center;
border-bottom: 1px solid $gray-light;
border-top: 1px solid $gray-light;
display: flex; display: flex;
margin-bottom: 1rem; margin-bottom: 1rem;
padding: 1rem 0;
position: relative; position: relative;
&:hover { &:hover {
.assigned-to { .assigned-to {
@ -18,11 +21,31 @@
max-width: 2rem; max-width: 2rem;
} }
.user-avatar { .user-avatar {
flex-basis: 4rem; flex-basis: 3rem;
flex-shrink: 0; flex-shrink: 0;
position: relative;
img { img {
width: 100%; 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 { .assigned-to {
flex-grow: 1; flex-grow: 1;
@ -32,12 +55,12 @@
@extend %light; @extend %light;
color: $gray; color: $gray;
display: block; display: block;
margin: .2rem 0 .25rem;
} }
.user-assigned { .user-assigned {
@extend %large; @extend %large;
color: $primary; color: $primary;
cursor: default; cursor: default;
line-height: 1.5rem;
&.editable { &.editable {
cursor: pointer; cursor: pointer;
} }
@ -54,7 +77,7 @@
opacity: 0; opacity: 0;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 2rem;
&:hover { &:hover {
color: $red; color: $red;
} }

View File

@ -507,18 +507,23 @@
} }
.lb-create-edit-userstory { .lb-create-edit-userstory {
.points-per-role {
flex-direction: row;
flex-wrap: wrap;
margin: 0;
}
.ticket-role-points { .ticket-role-points {
flex-grow: 1; margin: .1rem;
flex-shrink: 1; min-width: 20%;
max-width: calc(100% * (1/6) - .2rem);
&:first-child { &:first-child {
margin-left: 0; margin-left: 0;
} }
&:nth-child(5n+5) { &:nth-child(4n + 4) {
margin-right: 0; margin-right: 0;
} }
&:last-child {
margin: .1rem 0;
min-width: 100%;
} }
.points-per-role {
margin-bottom: 0;
} }
} }

View File

@ -49,9 +49,13 @@ tg-project-menu {
} }
} }
} }
svg path { svg {
max-height: 1.5rem;
max-width: 1.5rem;
path {
opacity: 1; opacity: 1;
} }
}
span { span {
display: block; display: block;
} }

View File

@ -1,23 +1,53 @@
.ticket-data { .ticket-header {
margin: 1.5rem 0 2rem;
.ticket-title { .ticket-title {
@extend %larger; @extend %larger;
@extend %light; @extend %light;
margin: 1.5rem 0 2rem;
text-transform: uppercase; text-transform: uppercase;
span { vertical-align: sub;
margin-right: .25rem; }
&:last-child { .detail-status {
@extend %large; @extend %small;
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;
} }
.ticket-data-container { .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 %small;
@extend %normal; @extend %normal;
margin-bottom: 1rem; margin-bottom: 1rem;
.icon { .icon {
margin-left: .25rem; margin-left: .25rem;
} }
}
.ticket-status {
&:last-child {
margin: 0;
} }
.level { .level {
display: inline-block; display: inline-block;
@ -29,29 +59,6 @@
float: right; float: right;
text-transform: lowercase; 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 { .clickable {
&:hover { &:hover {
background: darken($whitish, 10%); background: darken($whitish, 10%);
@ -59,142 +66,153 @@
} }
} }
.type-data { .type-data {
background: darken($whitish, 5%);
margin-bottom: .5rem;
padding: .5rem;
padding-right: 1rem;
position: relative; position: relative;
transition: background .2s ease-in;
.pop-type { .pop-type {
@include popover(150px, '', 30px, '', ''); @include popover(150px, '', 30px, '', '');
} }
} }
.severity-data { .severity-data {
background: darken($whitish, 5%);
margin-bottom: .5rem;
padding: .5rem;
padding-right: 1rem;
position: relative; position: relative;
transition: background .2s ease-in;
.pop-severity { .pop-severity {
@include popover(150px, '', 30px, '', ''); @include popover(150px, '', 30px, '', '');
} }
} }
.priority-data { .priority-data {
background: darken($whitish, 5%);
margin-bottom: .5rem;
padding: .5rem;
padding-right: 1rem;
position: relative; position: relative;
transition: background .2s ease-in;
.pop-priority { .pop-priority {
@include popover(150px, '', 30px, '', ''); @include popover(150px, '', 30px, '', '');
} }
} }
.status-data {
position: relative;
.pop-status {
@include popover(150px, '', 30px, '', '');
}
}
} }
.ticket-track-buttons { .ticket-watch {
.track-inner { .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 %light;
@extend %small; @extend %small;
background: darken($whitish, 5%); background: $gray-light;
color: $white;
flex: 1;
padding: .25rem; padding: .25rem;
text-align: center;
text-transform: uppercase; text-transform: uppercase;
transition: background .25s; transition: background .25s;
&:hover { path {
background: darken($whitish, 10%); fill: $white;
}
}
.track-button {
width: 100%;
}
.active {
.track-button-counter {
background: rgba($grayer, .5);
} }
&:hover { &:hover {
.track-inner { background: $primary-light;
background: rgba($primary-light, .2);
}
} }
&.is-hover { &.is-hover {
.track-inner {
background: $red; background: $red;
color: $whitish; color: $whitish;
transition: background .3s; transition: background .3s;
} svg {
path {
fill: $red-light; fill: $red-light;
} }
} }
} &.active {
.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; background: $primary-light;
color: $whitish; &:hover {
transition: background .3s linear; background: $red-light;
}
svg {
fill: $white;
} }
} }
}
.ticket-watch-button {
margin-right: .25rem;
} }
} }
.ticket-detail-settings { .ticket-detail-settings {
display: flex;
justify-content: center;
margin-top: 2rem; margin-top: 2rem;
label, label,
.button { .item-block,
display: block; .item-unblock,
margin-bottom: .5rem; .promote-button,
text-align: center; .button-delete {
&.editable { 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; cursor: pointer;
&:hover {
background: $gray;
}
}
&.active {
background: $primary-light;
} }
+input { +input {
display: none; display: none;
} }
} }
.loading-spinner { .item-block,
@extend %loading-spinner; .item-unblock {
} display: none;
.button-gray { &.is-active {
background: $gray-light; display: inline-block;
&:hover {
background: $gray-light;
}
&.editable {
&:hover {
background: $grayer;
cursor: pointer;
} }
} }
&.active { .item-unblock {
background: $primary; background: $red;
} }
} .button-delete {
.item-block { background: $red-light;
&.editable {
&:hover { &:hover {
background: $red; background: $red;
cursor: pointer; cursor: pointer;
} }
} }
img {
max-height: 1.25rem;
max-width: 1.25rem;
width: 100%;
} }
.button-red { svg {
display: block; fill: $white;
margin-top: 2rem; height: 100%;
max-height: 1.25rem;
max-width: 1.25rem;
width: 100%;
} }
} }

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path
d="M106.8 0v54.4H-.4v239h176.8v-25H24.6v-189h24v95h237v-95h24V176h25V54.3H231.8V0h-125zm25 25h75v29.4h-75V25zM73.6 79.4h187v70h-187v-70zm81 20v28.5h25V99.2h-25zM200.4 200v200h200V200h-200zm25 25h150v27.4L360.8 240l-74 88-49.8-42-11.6 14v-75zm150 36.7V375h-150v-66l45.2 38.2 19 16 16.2-19 69.6-82.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 396 B

4
app/svg/iocaine.svg Normal file
View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path
d="M239.7 0c-1.4 0-2.8 0-4 .3-27.7.5-55.4-.7-83 .6C138 4 129 21.7 135 35.5c.8 5 3.6 11.5 3.5 16h-28.8v25.3h20c-1.2 11.5-13.8 16.4-22.4 21.8C89 109 70.5 124 66.7 145.8c-4 20.5-.5 41.5-1.7 62 .3 56.4-1 112.8.7 169 2.5 14.4 17.2 24.6 31.4 23 54.4.4 108.8 0 163 .2 18-.3 35.8.4 53.5-1 13.7-3.3 23-17.4 21.5-31.2.5-55 0-110 .3-165-.3-18.2.3-36.6-1.2-54.8-3.8-22.5-22-39.2-41.4-49.4-9-5-20.4-10.5-22.4-21.7H290V64.7 51.5h-29c3-12.3 9.7-26 2.8-38.2-5-8.7-14.4-13.3-24-13.3zm-1.4 24.7c1.7 0 3.3.2 4 1.6-.6 4.8-3 9.2-4 14-1.4 3.3 0 8.6-2.8 11.2h-71.2c-1.8-8.8-5.7-17.8-5.8-26.6 2-.6 4 0 6-.2 23 .4 46 0 69 0 1.3.2 3 0 4.8 0zM154.8 77h91c0 16.5 12 30.4 26 38 14.3 8.7 32.8 17 37.5 34.8 2 4.6.6 7.2-4.8 5.7H89.7c1.4-15.3 14-27.2 27.3-33.8 14.8-8.5 32.4-18.2 36.3-36.3 1-2.5 0-7 1.5-8.5zm-18.6 103.7c15 6 23 21.2 35.3 30.8 6.6-4.7 14.2-7.8 22-9.2 14-3 28 2 40.5 8 11.8-9.6 18-18 28-25.8 6.3-6 17-3.3 17 5-8.2 14.5-21 23.4-32.5 34.6 8.5 12 12 27.4 8.5 41.6-.3 7.2-7.2 12-8 19 8 11.8 18.8 20 27.7 30.5 7.4 4.3 3.5 17.2-5 17-14.7-8.2-23.2-23.7-37-33-1.8 5.3 0 13.2-.3 19.6 1.4 6.4-3.5 12.7-10 13.3-12.7-.8-25.6 0-38.4-.5-7.4.5-10.3-7.8-9.8-14 0-5 3-13-3.3-15.4-12.7 6.2-20.8 17.5-34.4 26.7-4.8 6.6-16.2 1-15.6-6.5 10.2-16 27-25.3 40-38.6-15.4-15.5-15.2-42-2-58.8-7.8-10-18.2-18-26.8-27.3-7.3-3.8-4-16.7 4-16.8zM205 219h-2.2c-14.6 0-28.7 9.7-34 23.6-5.8 12.7.3 28.3 12 35.3 6.5 1.7 11 7.6 11.7 14.2 1.4 6.8-3 14.2.7 20.4 6.4 2.4 14.4 2.7 21 .4 2.2-7-.7-15.2.3-22.7 2.2-11 16-13.2 21-22.4 11-21-7.6-48.4-30.5-49zm-14.7 21.8c4.7 0 7.8 4.6 8.7 8.7 2 6.7-2.3 17-10.4 15.3-11.6-2.6-10.5-23.3 1.7-24zm27 0c4.4.2 7.2 4.2 8.2 8.2 2.3 6.7-1.8 17.2-10 15.8-11.7-2.3-11-23 1-24h1zM90 360.8c21.2 1 42.5-.2 63.8.3h156.6c0 4.7 2.4 13-4 14-15 1.4-29.8-.5-44.7.3-56.5-.2-113 .7-169.6-.5-4-3-2.7-10.2-2-14z" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,7 +1,3 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400.00001">
<!-- Created with Inkscape (http://www.inkscape.org/) --> <path d="M167 0C108.6 0 61.2 47.5 61.2 106v46.8H0V400h400V152.7h-61.2V106C338.8 47.5 291.4 0 233 0h-66zm0 25h66c45 0 80.8 36 80.8 81v46.8H86.2V106c0-45 35.8-81 80.8-81zM25 178h350V375H25V177.8zm162.5 51.4v89.6h25v-89.6h-25z" />
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 10.2367 12.115">
<g transform="translate(51.126 -417.22)">
<path class="lock" d="m-46.008 417.22c-1.886 0-3.4167 1.5307-3.4167 3.4167v1.033h-1.2265c-0.2632 0-0.4751 0.2264-0.4751 0.5072v6.6509c0 0.2808 0.2119 0.5072 0.4751 0.5072h9.2865c0.2632 0 0.4751-0.2264 0.4751-0.5072v-6.6509c0-0.2808-0.2119-0.5072-0.4751-0.5072h-1.2265v-1.033c0-1.886-1.5307-3.4167-3.4168-3.4167zm0 1.2986c1.1686 0 2.1195 0.9496 2.1195 2.1181v1.033h-4.2375v-1.033c0-1.1685 0.9495-2.1181 2.118-2.1181z"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 828 B

After

Width:  |  Height:  |  Size: 306 B

3
app/svg/project.svg Normal file
View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path d="M237.4 49.5v40h-186v49.7H0v211.3h400v-301H262.4zm25 25H375v251h-50V140h-.2v-.8H76.4v-24.7l186 1z"/>
</svg>

After

Width:  |  Height:  |  Size: 189 B

3
app/svg/promote.svg Normal file
View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0v400h400V0H0zm25 25h162.5v350H25V25zm187.5 0H375v98.5H212.5V25zm-106 19.3L33.8 117l17.4 17.4L94 91.6V358h25V91.6l42.8 42.8 17.4-17.3-72.7-72.7zm106 104.2H375v107H212.5v-107zm0 132H375V375H212.5v-94.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path
d="M158 0c-54.5 0-99 44.4-99 99 0 54.4 44.5 98.8 99 98.8 54.4 0 99-44.4 99-99C257 44.5 212.3 0 158 0zm0 25c41 0 74 33 74 74s-33 73.8-74 73.8-74-33-74-74S117 25 158 25zm42.4 175v200h200V200h-200zM158 213.6C70.2 213.6 0 292.2-.3 387.4V400h176.7v-25h-151c6-77 63.5-136.3 132.6-136.4 6.2 0 12.3.5 18.4 1.5V215c-6-.8-12.2-1.2-18.4-1.2zm67.4 11.4h150v27.4L360.8 240l-74 88-49.8-42-11.6 14v-75zm150 36.7V375h-150v-66l45.2 38.2 19 16 16.2-19 69.6-82.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 542 B

3
app/svg/trash.svg Normal file
View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path d="M106.8 0v56H0v25h46.8v319h305V81H400V56H291.8V0zm25 25h135v31h-135zm-60 56h35v267h25V81h55v267h25V81h55v267h25V81h35v294h-255z"/>
</svg>

After

Width:  |  Height:  |  Size: 219 B

3
app/svg/unlock.svg Normal file
View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 400 400.00001" xmlns="http://www.w3.org/2000/svg">
<path d="M167 0C110 0 63.4 45.4 61.3 102h25c2-43 37-77 80.7-77h66c45 0 80.8 36 80.8 81v46.7H0V400h400V152.7h-61.2V106C338.8 47.5 291.4 0 233 0zM25 177.8h350v197H25zm162.5 51.4v89.6h25v-89.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 274 B