commit
23fc1372d3
|
@ -71,16 +71,39 @@ NavigationUrlsDirective = ($navurls, $auth, $q, $location) ->
|
|||
parseNav = (data, $scope) ->
|
||||
[name, params] = _.map(data.split(":"), trim)
|
||||
if params
|
||||
params = _.map(params.split(","), trim)
|
||||
# split by 'xxx='
|
||||
# example
|
||||
# project=vm.timeline.getIn(['data', 'project', 'slug']), ref=vm.timeline.getIn(['obj', 'ref'])
|
||||
# ["", "project", "vm.timeline.getIn(['data', 'project', 'slug']), ", "ref", "vm.timeline.getIn(['obj', 'ref'])"]
|
||||
result = params.split(/(\w+)=/)
|
||||
|
||||
# remove empty string
|
||||
result = _.filter result, (str) -> return str.length
|
||||
|
||||
# remove , at the end of the string
|
||||
result = _.map result, (str) -> return trim(str.replace(/,$/g, ''))
|
||||
|
||||
params = []
|
||||
index = 0
|
||||
|
||||
# ['param1', 'value'] => [{'param1': 'value'}]
|
||||
while index < result.length
|
||||
obj = {}
|
||||
obj[result[index]] = result[index + 1]
|
||||
params.push obj
|
||||
index = index + 2
|
||||
else
|
||||
params = []
|
||||
values = _.map(params, (x) -> trim(x.split("=")[1]))
|
||||
|
||||
values = _.map params, (param) -> _.values(param)[0]
|
||||
promises = _.map(values, (x) -> bindOnceP($scope, x))
|
||||
|
||||
return $q.all(promises).then ->
|
||||
options = {}
|
||||
for item in params
|
||||
[key, value] = _.map(item.split("="), trim)
|
||||
for param in params
|
||||
key = Object.keys(param)[0]
|
||||
value = param[key]
|
||||
|
||||
options[key] = $scope.$eval(value)
|
||||
return [name, options]
|
||||
|
||||
|
|
|
@ -1248,6 +1248,7 @@
|
|||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
"US_UPDATED_WITH_NEW_VALUE": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}} to {{new_value}}",
|
||||
"US_UPDATED_POINTS": "{{username}} has updated the '{{role_name}}' role of the US {{obj_name}} to {{new_value}}",
|
||||
"ISSUE_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}}",
|
||||
"ISSUE_UPDATED_WITH_NEW_VALUE": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}} to {{new_value}}",
|
||||
"TASK_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} to {{new_value}}",
|
||||
|
|
|
@ -35,4 +35,4 @@ describe "tgFeedbackService", ->
|
|||
params = {
|
||||
"class": "lightbox lightbox-feedback lightbox-generic-form"
|
||||
}
|
||||
expect(mocks.tgLightboxFactory.create.calledWith("tg-lb-feedback", params)).to.be.true()
|
||||
expect(mocks.tgLightboxFactory.create.calledWith("tg-lb-feedback", params)).to.be.true
|
||||
|
|
|
@ -87,7 +87,7 @@ describe "dropdownUserDirective", () ->
|
|||
vm.logout()
|
||||
expect(mockTgAuth.logout.callCount).to.be.equal(1)
|
||||
expect(mockTgLocation.path.callCount).to.be.equal(1)
|
||||
expect(mockTgLocation.path.calledWith("/login")).to.be.true()
|
||||
expect(mockTgLocation.path.calledWith("/login")).to.be.true
|
||||
|
||||
it "dropdown user send feedback", () ->
|
||||
elm = createDirective()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// timeline-attachment directive
|
||||
div.activity-image-attachment
|
||||
blockquote
|
||||
a(href="{{::attachment.url}}", title="See {{::attachment.filename}}", target="_blank")
|
||||
img(ng-src="{{::attachment.thumb_url || attachment.url}}", alt="{{::attachment.filename}}")
|
||||
a(href="{{::attachment.get('url')}}", title="See {{::attachment.get('filename')}}", target="_blank")
|
||||
img(ng-src="{{::attachment.get('thumb_url') || attachment.get('url')}}", alt="{{::attachment.get('filename')}}")
|
||||
|
|
|
@ -8,7 +8,7 @@ UserTimelineAttachmentDirective = (template, $compile) ->
|
|||
return url.indexOf(extension, url - extension.length) != -1
|
||||
|
||||
link = (scope, el) ->
|
||||
is_image = isImage(scope.attachment.url)
|
||||
is_image = isImage(scope.attachment.get('url'))
|
||||
|
||||
if is_image
|
||||
templateHtml = template.get("user-timeline/user-timeline-attachment/user-timeline-attachment-image.html")
|
||||
|
|
|
@ -32,9 +32,9 @@ describe "userTimelineAttachmentDirective", () ->
|
|||
compile = $compile
|
||||
|
||||
it "attachment image template", () ->
|
||||
scope.attachment = {
|
||||
scope.attachment = Immutable.fromJS({
|
||||
url: "path/path/file.jpg"
|
||||
}
|
||||
})
|
||||
|
||||
mockTgTemplate.get
|
||||
.withArgs("user-timeline/user-timeline-attachment/user-timeline-attachment-image.html")
|
||||
|
@ -45,9 +45,9 @@ describe "userTimelineAttachmentDirective", () ->
|
|||
expect(elm.find('#image')).to.have.length(1)
|
||||
|
||||
it "attachment file template", () ->
|
||||
scope.attachment = {
|
||||
scope.attachment = Immutable.fromJS({
|
||||
url: "path/path/file.pdf"
|
||||
}
|
||||
})
|
||||
|
||||
mockTgTemplate.get
|
||||
.withArgs("user-timeline/user-timeline-attachment/user-timeline-attachment.html")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
div.single-attachment
|
||||
blockquote
|
||||
a(ng-href="{{ attachment.url }}", title="Click to download {{ attachment.filename }}", target="_blank")
|
||||
a(ng-href="{{ attachment.get('url') }}", title="Click to download {{ attachment.get('filename') }}", target="_blank")
|
||||
span.icon.icon-document
|
||||
span {{attachment.filename}}
|
||||
span {{attachment.get('filename')}}
|
||||
|
|
|
@ -14,74 +14,93 @@ class UserTimelineItemTitle
|
|||
'severity': 'ISSUES.FIELDS.SEVERITY',
|
||||
'priority': 'ISSUES.FIELDS.PRIORITY',
|
||||
'type': 'ISSUES.FIELDS.TYPE',
|
||||
'is_iocaine': 'TASK.FIELDS.IS_IOCAINE'
|
||||
'is_iocaine': 'TASK.FIELDS.IS_IOCAINE',
|
||||
'is_blocked': 'COMMON.FIELDS.IS_BLOCKED'
|
||||
}
|
||||
|
||||
_params: {
|
||||
username: (timeline, event) ->
|
||||
user = timeline.getIn(['data', 'user'])
|
||||
|
||||
if user.get('is_profile_visible')
|
||||
title_attr = @translate.instant('COMMON.SEE_USER_PROFILE', {username: user.get('username')})
|
||||
url = "user-profile:username=vm.timeline.getIn(['data', 'user', 'username'])"
|
||||
|
||||
return @._getLink(url, user.get('name'), title_attr)
|
||||
else
|
||||
return @._getUsernameSpan(user.get('name'))
|
||||
|
||||
field_name: (timeline, event) ->
|
||||
field_name = timeline.getIn(['data', 'value_diff', 'key'])
|
||||
|
||||
return @translate.instant(@._fieldTranslationKey[field_name])
|
||||
|
||||
project_name: (timeline, event) ->
|
||||
url = "project:project=vm.timeline.getIn(['data', 'project', 'slug'])"
|
||||
|
||||
return @._getLink(url, timeline.getIn(["data", "project", "name"]))
|
||||
|
||||
new_value: (timeline, event) ->
|
||||
if _.isArray(timeline.getIn(["data", "value_diff", "value"]).toJS())
|
||||
value = timeline.getIn(["data", "value_diff", "value"]).get(1)
|
||||
|
||||
# assigned to unasigned
|
||||
if value == null && timeline.getIn(["data", "value_diff", "key"]) == 'assigned_to'
|
||||
value = @translate.instant('ACTIVITY.VALUES.UNASSIGNED')
|
||||
|
||||
return value
|
||||
else
|
||||
return timeline.getIn(["data", "value_diff", "value"]).first().get(1)
|
||||
|
||||
sprint_name: (timeline, event) ->
|
||||
url = "project-taskboard:project=vm.timeline.getIn(['data', 'project', 'slug']),sprint=vm.timeline.getIn(['data', 'milestone', 'slug'])"
|
||||
|
||||
return @._getLink(url, timeline.getIn(['data', 'milestone', 'name']))
|
||||
|
||||
us_name: (timeline, event) ->
|
||||
obj = @._getTimelineObj(timeline, event).get('userstory')
|
||||
|
||||
event_us = {obj: 'parent_userstory'}
|
||||
url = @._getDetailObjUrl(event_us)
|
||||
|
||||
text = '#' + obj.get('ref') + ' ' + obj.get('subject')
|
||||
|
||||
return @._getLink(url, text)
|
||||
|
||||
obj_name: (timeline, event) ->
|
||||
obj = @._getTimelineObj(timeline, event)
|
||||
url = @._getDetailObjUrl(event)
|
||||
|
||||
if event.obj == 'wikipage'
|
||||
text = unslugify(obj.get('slug'))
|
||||
else if event.obj == 'milestone'
|
||||
text = obj.get('name')
|
||||
else
|
||||
text = '#' + obj.get('ref') + ' ' + obj.get('subject')
|
||||
|
||||
return @._getLink(url, text)
|
||||
|
||||
role_name: (timeline, event) ->
|
||||
return timeline.getIn(['data', 'value_diff', 'value']).keySeq().first()
|
||||
}
|
||||
|
||||
constructor: (@translate) ->
|
||||
|
||||
|
||||
_translateTitleParams: (param, timeline, event) ->
|
||||
if param == "username"
|
||||
user = timeline.data.user
|
||||
title_attr = @translate.instant('COMMON.SEE_USER_PROFILE', {username: user.username})
|
||||
url = 'user-profile:username=vm.activity.user.username'
|
||||
|
||||
return @._getLink(url, user.name, title_attr)
|
||||
|
||||
else if param == 'field_name'
|
||||
field_name = Object.keys(timeline.data.values_diff)[0]
|
||||
|
||||
return @translate.instant(@._fieldTranslationKey[field_name])
|
||||
|
||||
else if param == 'project_name'
|
||||
url = 'project:project=vm.activity.project.slug'
|
||||
|
||||
return @._getLink(url, timeline.data.project.name)
|
||||
|
||||
else if param == 'new_value'
|
||||
field_name = Object.keys(timeline.data.values_diff)[0]
|
||||
|
||||
return timeline.data.values_diff[field_name][1]
|
||||
|
||||
else if param == 'sprint_name'
|
||||
url = 'project-taskboard:project=vm.activity.project.slug,sprint=vm.activity.sprint.slug'
|
||||
|
||||
return @._getLink(url, timeline.data.milestone.name)
|
||||
|
||||
else if param == 'us_name'
|
||||
obj = @._getTimelineObj(timeline, event).userstory
|
||||
|
||||
event_us = {obj: 'parent_userstory'}
|
||||
url = @._getDetailObjUrl(event_us)
|
||||
|
||||
text = '#' + obj.ref + ' ' + obj.subject
|
||||
|
||||
return @._getLink(url, text)
|
||||
|
||||
else if param == 'obj_name'
|
||||
obj = @._getTimelineObj(timeline, event)
|
||||
url = @._getDetailObjUrl(event)
|
||||
|
||||
if event.obj == 'wikipage'
|
||||
text = unslugify(obj.slug)
|
||||
else if event.obj == 'milestone'
|
||||
text = obj.name
|
||||
else
|
||||
text = '#' + obj.ref + ' ' + obj.subject
|
||||
|
||||
return @._getLink(url, text)
|
||||
return @._params[param].call(this, timeline, event)
|
||||
|
||||
_getTimelineObj: (timeline, event) ->
|
||||
return timeline.data[event.obj]
|
||||
return timeline.getIn(['data', event.obj])
|
||||
|
||||
_getDetailObjUrl: (event) ->
|
||||
url = {
|
||||
"issue": ["project-issues-detail", ":project=vm.activity.project.slug,ref=vm.activity.obj.ref"],
|
||||
"wikipage": ["project-wiki-page", ":project=vm.activity.project.slug,slug=vm.activity.obj.slug"],
|
||||
"task": ["project-tasks-detail", ":project=vm.activity.project.slug,ref=vm.activity.obj.ref"],
|
||||
"userstory": ["project-userstories-detail", ":project=vm.activity.project.slug,ref=vm.activity.obj.ref"],
|
||||
"parent_userstory": ["project-userstories-detail", ":project=vm.activity.project.slug,ref=vm.activity.obj.userstory.ref"],
|
||||
"milestone": ["project-taskboard", ":project=vm.activity.project.slug,sprint=vm.activity.obj.slug"]
|
||||
"issue": ["project-issues-detail", ":project=vm.timeline.getIn(['data', 'project', 'slug']),ref=vm.timeline.getIn(['obj', 'ref'])"],
|
||||
"wikipage": ["project-wiki-page", ":project=vm.timeline.getIn(['data', 'project', 'slug']),slug=vm.timeline.getIn(['obj', 'ref'])"],
|
||||
"task": ["project-tasks-detail", ":project=vm.timeline.getIn(['data', 'project', 'slug']),ref=vm.timeline.getIn(['obj', 'ref'])"],
|
||||
"userstory": ["project-userstories-detail", ":project=vm.timeline.getIn(['data', 'project', 'slug']),ref=vm.timeline.getIn(['obj', 'ref'])"],
|
||||
"parent_userstory": ["project-userstories-detail", ":project=vm.timeline.getIn(['data', 'project', 'slug']),ref=vm.timeline.getIn(['obj', 'userstory', 'ref'])"],
|
||||
"milestone": ["project-taskboard", ":project=vm.timeline.getIn(['data', 'project', 'slug']),ref=vm.timeline.getIn(['obj', 'ref'])"]
|
||||
}
|
||||
|
||||
return url[event.obj][0] + url[event.obj][1]
|
||||
|
@ -95,6 +114,14 @@ class UserTimelineItemTitle
|
|||
.attr('title', title)
|
||||
.prop('outerHTML')
|
||||
|
||||
_getUsernameSpan: (text) ->
|
||||
title = title || text
|
||||
|
||||
return $('<span>')
|
||||
.addClass('username')
|
||||
.text(text)
|
||||
.prop('outerHTML')
|
||||
|
||||
_getParams: (timeline, event, timeline_type) ->
|
||||
params = {}
|
||||
|
||||
|
|
|
@ -32,14 +32,15 @@ describe "tgUserTimelineItemTitle", ->
|
|||
_setup()
|
||||
|
||||
it "title with username", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
user: {
|
||||
username: 'xx',
|
||||
name: 'oo'
|
||||
name: 'oo',
|
||||
is_profile_visible: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
|
@ -49,11 +50,45 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
mockTranslate.instant
|
||||
.withArgs('COMMON.SEE_USER_PROFILE', {username: timeline.data.user.username})
|
||||
.withArgs('COMMON.SEE_USER_PROFILE', {username: timeline.getIn(['data', 'user', 'username'])})
|
||||
.returns('user-param')
|
||||
|
||||
usernamelink = sinon.match ((value) ->
|
||||
return value.username == '<a tg-nav="user-profile:username=vm.activity.user.username" title="user-param">oo</a>'
|
||||
return value.username == '<a tg-nav="user-profile:username=vm.timeline.getIn([\'data\', \'user\', \'username\'])" title="user-param">oo</a>'
|
||||
), "usernamelink"
|
||||
|
||||
mockTranslate.instant
|
||||
.withArgs('TITLE_USER_NAME', usernamelink)
|
||||
.returns('title_ok')
|
||||
|
||||
title = mySvc.getTitle(timeline, event, type)
|
||||
|
||||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title with username not visible", () ->
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
user: {
|
||||
username: 'xx',
|
||||
name: 'oo',
|
||||
is_profile_visible: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
type = {
|
||||
key: 'TITLE_USER_NAME',
|
||||
translate_params: ['username']
|
||||
}
|
||||
|
||||
mockTranslate.instant
|
||||
.withArgs('COMMON.SEE_USER_PROFILE', {username: timeline.getIn(['data', 'user', 'username'])})
|
||||
.returns('user-param')
|
||||
|
||||
usernamelink = sinon.match ((value) ->
|
||||
return value.username == '<span class="username">oo</span>'
|
||||
), "usernamelink"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -65,13 +100,13 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title with a field name", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
values_diff: {
|
||||
status: {}
|
||||
value_diff: {
|
||||
key: 'status'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
|
@ -92,19 +127,19 @@ describe "tgUserTimelineItemTitle", ->
|
|||
.withArgs('TITLE_FIELD', fieldparam)
|
||||
.returns('title_ok')
|
||||
|
||||
|
||||
title = mySvc.getTitle(timeline, event, type)
|
||||
|
||||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title with new value", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
values_diff: {
|
||||
status: ['old', 'new']
|
||||
value_diff: {
|
||||
key: 'status',
|
||||
value: ['old', 'new']
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
|
@ -122,13 +157,13 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("new_value_ok")
|
||||
|
||||
it "title with project name", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
project: {
|
||||
name: "project_name"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
|
@ -138,7 +173,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
projectparam = sinon.match ((value) ->
|
||||
return value.project_name == '<a tg-nav="project:project=vm.activity.project.slug" title="project_name">project_name</a>'
|
||||
return value.project_name == '<a tg-nav="project:project=vm.timeline.getIn([\'data\', \'project\', \'slug\'])" title="project_name">project_name</a>'
|
||||
), "projectparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -150,13 +185,13 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title with sprint name", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
milestone: {
|
||||
name: "milestone_name"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {}
|
||||
|
||||
|
@ -166,7 +201,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
milestoneparam = sinon.match ((value) ->
|
||||
return value.sprint_name == '<a tg-nav="project-taskboard:project=vm.activity.project.slug,sprint=vm.activity.sprint.slug" title="milestone_name">milestone_name</a>'
|
||||
return value.sprint_name == '<a tg-nav="project-taskboard:project=vm.timeline.getIn([\'data\', \'project\', \'slug\']),sprint=vm.timeline.getIn([\'data\', \'milestone\', \'slug\'])" title="milestone_name">milestone_name</a>'
|
||||
), "milestoneparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -178,14 +213,14 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title with object", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
issue: {
|
||||
ref: '123',
|
||||
subject: 'subject'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {
|
||||
obj: 'issue',
|
||||
|
@ -197,7 +232,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
objparam = sinon.match ((value) ->
|
||||
return value.obj_name == '<a tg-nav="project-issues-detail:project=vm.activity.project.slug,ref=vm.activity.obj.ref" title="#123 subject">#123 subject</a>'
|
||||
return value.obj_name == '<a tg-nav="project-issues-detail:project=vm.timeline.getIn([\'data\', \'project\', \'slug\']),ref=vm.timeline.getIn([\'obj\', \'ref\'])" title="#123 subject">#123 subject</a>'
|
||||
), "objparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -209,13 +244,13 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title obj wiki", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
wikipage: {
|
||||
slug: 'slug-wiki',
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {
|
||||
obj: 'wikipage',
|
||||
|
@ -227,7 +262,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
objparam = sinon.match ((value) ->
|
||||
return value.obj_name == '<a tg-nav="project-wiki-page:project=vm.activity.project.slug,slug=vm.activity.obj.slug" title="Slug wiki">Slug wiki</a>'
|
||||
return value.obj_name == '<a tg-nav="project-wiki-page:project=vm.timeline.getIn([\'data\', \'project\', \'slug\']),slug=vm.timeline.getIn([\'obj\', \'ref\'])" title="Slug wiki">Slug wiki</a>'
|
||||
), "objparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -239,13 +274,13 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "title obj milestone", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
milestone: {
|
||||
name: 'milestone_name',
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {
|
||||
obj: 'milestone',
|
||||
|
@ -257,7 +292,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
objparam = sinon.match ((value) ->
|
||||
return value.obj_name == '<a tg-nav="project-taskboard:project=vm.activity.project.slug,sprint=vm.activity.obj.slug" title="milestone_name">milestone_name</a>'
|
||||
return value.obj_name == '<a tg-nav="project-taskboard:project=vm.timeline.getIn([\'data\', \'project\', \'slug\']),ref=vm.timeline.getIn([\'obj\', \'ref\'])" title="milestone_name">milestone_name</a>'
|
||||
), "objparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
@ -269,7 +304,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "task title with us_name", () ->
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
data: {
|
||||
task: {
|
||||
name: 'task_name',
|
||||
|
@ -279,7 +314,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event = {
|
||||
obj: 'task',
|
||||
|
@ -291,41 +326,7 @@ describe "tgUserTimelineItemTitle", ->
|
|||
}
|
||||
|
||||
objparam = sinon.match ((value) ->
|
||||
return value.us_name == '<a tg-nav="project-userstories-detail:project=vm.activity.project.slug,ref=vm.activity.obj.userstory.ref" title="#2 subject">#2 subject</a>'
|
||||
), "objparam"
|
||||
|
||||
mockTranslate.instant
|
||||
.withArgs('TITLE_OBJ', objparam)
|
||||
.returns('title_ok')
|
||||
|
||||
title = mySvc.getTitle(timeline, event, type)
|
||||
|
||||
expect(title).to.be.equal("title_ok")
|
||||
|
||||
it "task title with us_name", () ->
|
||||
timeline = {
|
||||
data: {
|
||||
task: {
|
||||
name: 'task_name',
|
||||
userstory: {
|
||||
ref: 2
|
||||
subject: 'subject'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event = {
|
||||
obj: 'task',
|
||||
}
|
||||
|
||||
type = {
|
||||
key: 'TITLE_OBJ',
|
||||
translate_params: ['us_name']
|
||||
}
|
||||
|
||||
objparam = sinon.match ((value) ->
|
||||
return value.us_name == '<a tg-nav="project-userstories-detail:project=vm.activity.project.slug,ref=vm.activity.obj.userstory.ref" title="#2 subject">#2 subject</a>'
|
||||
return value.us_name == '<a tg-nav="project-userstories-detail:project=vm.timeline.getIn([\'data\', \'project\', \'slug\']),ref=vm.timeline.getIn([\'obj\', \'userstory\', \'ref\'])" title="#2 subject">#2 subject</a>'
|
||||
), "objparam"
|
||||
|
||||
mockTranslate.instant
|
||||
|
|
|
@ -6,10 +6,10 @@ timelineType = (timeline, event) ->
|
|||
key: 'TIMELINE.NEW_MEMBER',
|
||||
translate_params: ['project_name']
|
||||
member: (timeline) ->
|
||||
return {
|
||||
user: timeline.data.user,
|
||||
role: timeline.data.role
|
||||
}
|
||||
return Immutable.Map({
|
||||
user: timeline.getIn(['data', 'user']),
|
||||
role: timeline.getIn(['data', 'role'])
|
||||
})
|
||||
},
|
||||
{ # NewProject
|
||||
check: (timeline, event) ->
|
||||
|
@ -17,11 +17,13 @@ timelineType = (timeline, event) ->
|
|||
key: 'TIMELINE.NEW_PROJECT',
|
||||
translate_params: ['username', 'project_name'],
|
||||
description: (timeline) ->
|
||||
return timeline.data.project.description
|
||||
return timeline.getIn(['data', 'project', 'description'])
|
||||
},
|
||||
{ # NewAttachment
|
||||
check: (timeline, event) ->
|
||||
return event.type == 'change' && timeline.data.values_diff.attachments
|
||||
return event.type == 'change' &&
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'attachments'
|
||||
key: 'TIMELINE.UPLOAD_ATTACHMENT',
|
||||
translate_params: ['username', 'obj_name']
|
||||
},
|
||||
|
@ -45,13 +47,13 @@ timelineType = (timeline, event) ->
|
|||
},
|
||||
{ # NewTask
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' && event.type == 'create' && !timeline.data.task.userstory
|
||||
return event.obj == 'task' && event.type == 'create' && !timeline.getIn(['data', 'task', 'userstory'])
|
||||
key: 'TIMELINE.TASK_CREATED',
|
||||
translate_params: ['username', 'project_name', 'obj_name']
|
||||
},
|
||||
{ # NewTask with US
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' && event.type == 'create' && timeline.data.task.userstory
|
||||
return event.obj == 'task' && event.type == 'create' && timeline.getIn(['data', 'task', 'userstory'])
|
||||
key: 'TIMELINE.TASK_CREATED_WITH_US',
|
||||
translate_params: ['username', 'project_name', 'obj_name', 'us_name']
|
||||
},
|
||||
|
@ -63,41 +65,45 @@ timelineType = (timeline, event) ->
|
|||
},
|
||||
{ # NewUsComment
|
||||
check: (timeline, event) ->
|
||||
return timeline.data.comment && event.obj == 'userstory'
|
||||
return timeline.getIn(['data', 'comment']) && event.obj == 'userstory'
|
||||
key: 'TIMELINE.NEW_COMMENT_US',
|
||||
translate_params: ['username', 'obj_name'],
|
||||
description: (timeline) ->
|
||||
return $(timeline.data.comment_html).text()
|
||||
return $(timeline.getIn(['data', 'comment_html'])).text()
|
||||
},
|
||||
{ # NewIssueComment
|
||||
check: (timeline, event) ->
|
||||
return timeline.data.comment && event.obj == 'issue'
|
||||
return timeline.getIn(['data', 'comment']) && event.obj == 'issue'
|
||||
key: 'TIMELINE.NEW_COMMENT_ISSUE',
|
||||
translate_params: ['username', 'obj_name'],
|
||||
description: (timeline) ->
|
||||
return $(timeline.data.comment_html).text()
|
||||
return $(timeline.getIn(['data', 'comment_html'])).text()
|
||||
},
|
||||
{ # NewTaskComment
|
||||
check: (timeline, event) ->
|
||||
return timeline.data.comment && event.obj == 'task'
|
||||
return timeline.getIn(['data', 'comment']) && event.obj == 'task'
|
||||
key: 'TIMELINE.NEW_COMMENT_TASK'
|
||||
translate_params: ['username', 'obj_name'],
|
||||
description: (timeline) ->
|
||||
return $(timeline.data.comment_html).text()
|
||||
return $(timeline.getIn(['data', 'comment_html'])).text()
|
||||
},
|
||||
{ # UsToMilestone
|
||||
check: (timeline, event, field_name) ->
|
||||
if field_name == 'milestone' && event.type == 'change'
|
||||
return timeline.data.values_diff.milestone[0] == null
|
||||
check: (timeline, event) ->
|
||||
if timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'milestone' &&
|
||||
event.type == 'change'
|
||||
return timeline.getIn(['data', 'value_diff', 'value']).get(0) == null
|
||||
|
||||
return false
|
||||
key: 'TIMELINE.US_ADDED_MILESTONE',
|
||||
translate_params: ['username', 'obj_name', 'sprint_name']
|
||||
},
|
||||
{ # UsToBacklog
|
||||
check: (timeline, event, field_name) ->
|
||||
if field_name == 'milestone' && event.type == 'change'
|
||||
return timeline.data.values_diff.milestone[1] == null
|
||||
check: (timeline, event) ->
|
||||
if timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'milestone' &&
|
||||
event.type == 'change'
|
||||
return timeline.getIn(['data', 'value_diff', 'value']).get(1) == null
|
||||
|
||||
return false
|
||||
key: 'TIMELINE.US_REMOVED_FROM_MILESTONE',
|
||||
|
@ -105,22 +111,26 @@ timelineType = (timeline, event) ->
|
|||
},
|
||||
{ # Blocked
|
||||
check: (timeline, event) ->
|
||||
if event.type == 'change' && timeline.data.values_diff.is_blocked
|
||||
return timeline.data.values_diff.is_blocked[1] == true
|
||||
if timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'blocked' &&
|
||||
event.type == 'change'
|
||||
return timeline.getIn(['data', 'value_diff', 'value', 'is_blocked']).get(1) == true
|
||||
|
||||
return false
|
||||
key: 'TIMELINE.BLOCKED',
|
||||
translate_params: ['username', 'obj_name'],
|
||||
description: (timeline) ->
|
||||
if timeline.data.values_diff.blocked_note_html
|
||||
return $(timeline.data.values_diff.blocked_note_html[1]).text()
|
||||
if timeline.hasIn(['data', 'value_diff', 'value', 'blocked_note_html'])
|
||||
return $(timeline.getIn(['data', 'value_diff', 'value', 'blocked_note_html']).get(1)).text()
|
||||
else
|
||||
return false
|
||||
},
|
||||
{ # UnBlocked
|
||||
check: (timeline, event) ->
|
||||
if event.type == 'change' && timeline.data.values_diff.is_blocked
|
||||
return timeline.data.values_diff.is_blocked[1] == false
|
||||
if timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'blocked' &&
|
||||
event.type == 'change'
|
||||
return timeline.getIn(['data', 'value_diff', 'value', 'is_blocked']).get(1) == false
|
||||
|
||||
return false
|
||||
key: 'TIMELINE.UNBLOCKED',
|
||||
|
@ -138,74 +148,83 @@ timelineType = (timeline, event) ->
|
|||
key: 'TIMELINE.WIKI_UPDATED',
|
||||
translate_params: ['username', 'obj_name']
|
||||
},
|
||||
{ # UsUpdated
|
||||
{ # UsUpdated points
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'userstory' &&
|
||||
event.type == 'change' &&
|
||||
!timeline.data.values_diff.description_diff
|
||||
key: 'TIMELINE.US_UPDATED_WITH_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value']
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'points'
|
||||
key: 'TIMELINE.US_UPDATED_POINTS',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value', 'role_name']
|
||||
},
|
||||
{ # UsUpdated description
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'userstory' &&
|
||||
event.type == 'change' &&
|
||||
timeline.data.values_diff.description_diff
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'description_diff'
|
||||
key: 'TIMELINE.US_UPDATED',
|
||||
translate_params: ['username', 'field_name', 'obj_name']
|
||||
},
|
||||
{ # IssueUpdated
|
||||
{ # UsUpdated general
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'issue' &&
|
||||
event.type == 'change' &&
|
||||
!timeline.data.values_diff.description_diff
|
||||
key: 'TIMELINE.ISSUE_UPDATED_WITH_NEW_VALUE',
|
||||
return event.obj == 'userstory' &&
|
||||
event.type == 'change'
|
||||
key: 'TIMELINE.US_UPDATED_WITH_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value']
|
||||
},
|
||||
{ # IssueUpdated description
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'issue' &&
|
||||
event.type == 'change' &&
|
||||
timeline.data.values_diff.description_diff
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'description_diff'
|
||||
key: 'TIMELINE.ISSUE_UPDATED',
|
||||
translate_params: ['username', 'field_name', 'obj_name']
|
||||
},
|
||||
{ # TaskUpdated
|
||||
{ # IssueUpdated general
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
!timeline.data.task.userstory &&
|
||||
!timeline.data.values_diff.description_diff
|
||||
key: 'TIMELINE.TASK_UPDATED_WITH_NEW_VALUE',
|
||||
return event.obj == 'issue' &&
|
||||
event.type == 'change'
|
||||
key: 'TIMELINE.ISSUE_UPDATED_WITH_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value']
|
||||
},
|
||||
{ # TaskUpdated description
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
!timeline.data.task.userstory &&
|
||||
timeline.data.values_diff.description_diff
|
||||
!timeline.getIn('data', 'task', 'userstory') &&
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'description_diff'
|
||||
key: 'TIMELINE.TASK_UPDATED',
|
||||
translate_params: ['username', 'field_name', 'obj_name']
|
||||
},
|
||||
{ # TaskUpdated with US
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
timeline.data.task.userstory &&
|
||||
!timeline.data.values_diff.description_diff
|
||||
key: 'TIMELINE.TASK_UPDATED_WITH_US_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'us_name', 'new_value']
|
||||
},
|
||||
{ # TaskUpdated with US description
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
timeline.data.task.userstory &&
|
||||
timeline.data.values_diff.description_diff
|
||||
timeline.getIn('data', 'task', 'userstory') &&
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'description_diff'
|
||||
key: 'TIMELINE.TASK_UPDATED_WITH_US',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'us_name']
|
||||
},
|
||||
{ # TaskUpdated general
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
!timeline.getIn(['data', 'task', 'userstory'])
|
||||
key: 'TIMELINE.TASK_UPDATED_WITH_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value']
|
||||
},
|
||||
{ # TaskUpdated with US
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'task' &&
|
||||
event.type == 'change' &&
|
||||
timeline.getIn(['data', 'task', 'userstory'])
|
||||
key: 'TIMELINE.TASK_UPDATED_WITH_US_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'us_name', 'new_value']
|
||||
},
|
||||
{ # New User
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'user' && event.type == 'create'
|
||||
|
@ -214,11 +233,8 @@ timelineType = (timeline, event) ->
|
|||
}
|
||||
]
|
||||
|
||||
if timeline.data.values_diff
|
||||
field_name = Object.keys(timeline.data.values_diff)[0]
|
||||
|
||||
return _.find types, (obj) ->
|
||||
return obj.check(timeline, event, field_name)
|
||||
return obj.check(timeline, event)
|
||||
|
||||
class UserTimelineType
|
||||
getType: (timeline, event) -> timelineType(timeline, event)
|
||||
|
|
|
@ -5,28 +5,27 @@ class UserTimelineItemController
|
|||
]
|
||||
|
||||
constructor: (@userTimelineItemType, @userTimelineItemTitle) ->
|
||||
timeline = @.timeline.toJS()
|
||||
event = @.parseEventType(@.timeline.get('event_type'))
|
||||
type = @userTimelineItemType.getType(@.timeline, event)
|
||||
|
||||
event = @.parseEventType(timeline.event_type)
|
||||
type = @userTimelineItemType.getType(timeline, event)
|
||||
title = @userTimelineItemTitle.getTitle(@.timeline, event, type)
|
||||
|
||||
@.activity = {}
|
||||
@.timeline = @.timeline.set('title_html', title)
|
||||
|
||||
@.activity.user = timeline.data.user
|
||||
@.activity.project = timeline.data.project
|
||||
@.activity.sprint = timeline.data.milestone
|
||||
@.activity.title = @userTimelineItemTitle.getTitle(timeline, event, type)
|
||||
@.activity.created_formated = moment(timeline.created).fromNow()
|
||||
@.activity.obj = @.getObject(timeline, event)
|
||||
@.timeline = @.timeline.set('obj', @.getObject(@.timeline, event))
|
||||
|
||||
if type.description
|
||||
@.activity.description = type.description(timeline)
|
||||
@.timeline = @.timeline.set('description', type.description(@.timeline))
|
||||
|
||||
if type.member
|
||||
@.activity.member = type.member(timeline)
|
||||
@.timeline = @.timeline.set('member', type.member(@.timeline))
|
||||
|
||||
if timeline.data.values_diff?.attachments
|
||||
@.activity.attachments = timeline.data.values_diff.attachments.new
|
||||
if @.timeline.hasIn(['data', 'value_diff', 'attachments', 'new'])
|
||||
@.timeline = @.timeline.set('attachments', @.timeline.getIn(['data', 'value_diff', 'attachments', 'new']))
|
||||
|
||||
getObject: (timeline, event) ->
|
||||
if timeline.get('data').get(event.obj)
|
||||
return timeline.get('data').get(event.obj)
|
||||
|
||||
parseEventType: (event_type) ->
|
||||
event_type = event_type.split(".")
|
||||
|
@ -37,9 +36,5 @@ class UserTimelineItemController
|
|||
type: event_type[2]
|
||||
}
|
||||
|
||||
getObject: (timeline, event) ->
|
||||
if timeline.data[event.obj]
|
||||
return timeline.data[event.obj]
|
||||
|
||||
angular.module("taigaUserTimeline")
|
||||
.controller("UserTimelineItem", UserTimelineItemController)
|
||||
|
|
|
@ -43,16 +43,23 @@ describe "UserTimelineItemController", ->
|
|||
type: 'created'
|
||||
}
|
||||
|
||||
timeline = {
|
||||
timeline = Immutable.fromJS({
|
||||
event_type: 'issues.issue.created',
|
||||
data: {
|
||||
user: 'user_fake',
|
||||
project: 'project_fake',
|
||||
milestone: 'milestone_fake',
|
||||
created: new Date().getTime(),
|
||||
values_diff: {}
|
||||
issue: {
|
||||
id: 2
|
||||
},
|
||||
value_diff: {
|
||||
attachments: {
|
||||
new: "fakeAttachment"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
scope = {
|
||||
vm: {
|
||||
|
@ -69,36 +76,19 @@ describe "UserTimelineItemController", ->
|
|||
inject ($controller) ->
|
||||
controller = $controller
|
||||
|
||||
it "basic activity fields filled", () ->
|
||||
timeline = scope.vm.timeline
|
||||
timeline_immutable = Immutable.fromJS(timeline)
|
||||
|
||||
myCtrl = controller("UserTimelineItem", {$scope: scope}, {timeline: timeline_immutable})
|
||||
|
||||
expect(myCtrl.activity.user).to.be.equal(timeline.data.user)
|
||||
expect(myCtrl.activity.project).to.be.equal(timeline.data.project)
|
||||
expect(myCtrl.activity.sprint).to.be.equal(timeline.data.milestone)
|
||||
expect(myCtrl.activity.title).to.be.equal("fakeTitle")
|
||||
expect(myCtrl.activity.created_formated).to.have.length.above(1)
|
||||
|
||||
it "all activity fields filled", () ->
|
||||
timeline = scope.vm.timeline
|
||||
|
||||
attachment = "fakeAttachment"
|
||||
timeline.data.values_diff.attachments = {
|
||||
new: attachment
|
||||
}
|
||||
|
||||
description = "fakeDescription"
|
||||
member = "fakeMember"
|
||||
|
||||
mockType.description.withArgs(timeline).returns(description)
|
||||
mockType.member.withArgs(timeline).returns(member)
|
||||
mockType.description.returns(description)
|
||||
mockType.member.returns(member)
|
||||
|
||||
timeline_immutable = Immutable.fromJS(timeline)
|
||||
myCtrl = controller("UserTimelineItem", {$scope: scope}, {timeline: timeline})
|
||||
|
||||
myCtrl = controller("UserTimelineItem", {$scope: scope}, {timeline: timeline_immutable})
|
||||
|
||||
expect(myCtrl.activity.description).to.be.equal(description)
|
||||
expect(myCtrl.activity.member).to.be.equal(member)
|
||||
expect(myCtrl.activity.attachments).to.be.equal(attachment)
|
||||
expect(myCtrl.timeline.get('title_html')).to.be.equal("fakeTitle")
|
||||
expect(myCtrl.timeline.get('obj')).to.be.equal(myCtrl.timeline.getIn(["data", "issue"]))
|
||||
expect(myCtrl.timeline.get("description")).to.be.equal(description)
|
||||
expect(myCtrl.timeline.get("member")).to.be.equal(member)
|
||||
expect(myCtrl.timeline.get("attachments")).to.be.equal("fakeAttachment")
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
div.activity-item
|
||||
span.activity-date {{::vm.activity.created_formated}}
|
||||
span.activity-date {{::vm.timeline.get('created') | momentFromNow}}
|
||||
|
||||
div.activity-info(tg-user-timeline-title="vm.timeline")
|
||||
|
||||
div.activity-info
|
||||
div.profile-contact-picture
|
||||
a(tg-nav="user-profile:username=vm.activity.user.username", title="{{::vm.activity.user.name }}")
|
||||
img(ng-src="{{::vm.activity.user.photo || '/images/user-noimage.png'}}", alt="{{::vm.activity.user.name}}")
|
||||
// profile image with url
|
||||
div.profile-contact-picture(ng-if="vm.timeline.getIn(['data', 'user', 'is_profile_visible'])")
|
||||
a(tg-nav="user-profile:username=vm.timeline.getIn(['data', 'user', 'username'])", title="{{::vm.timeline.getIn(['data', 'user', 'name']) }}")
|
||||
img(ng-src="{{::vm.timeline.getIn(['data', 'user', 'photo']) || '/images/user-noimage.png'}}", alt="{{::vm.timeline.getIn(['data', 'user', 'name'])}}")
|
||||
// profile image without url
|
||||
div.profile-contact-picture(ng-if="!vm.timeline.getIn(['data', 'user', 'is_profile_visible'])")
|
||||
img(ng-src="{{::vm.timeline.getIn(['data', 'user', 'photo']) || '/images/user-noimage.png'}}", alt="{{::vm.timeline.getIn(['data', 'user', 'name'])}}")
|
||||
|
||||
p(tg-compile-html="vm.activity.title")
|
||||
p(tg-compile-html="vm.timeline.get('title_html')")
|
||||
|
||||
blockquote.activity-comment-quote(ng-if="::vm.activity.description")
|
||||
| {{::vm.activity.description | limitTo:300}}
|
||||
blockquote.activity-comment-quote(ng-if="::vm.timeline.get('description')")
|
||||
| {{::vm.timeline.get('description') | limitTo:300}}
|
||||
|
||||
.activity-member-view(ng-if="::vm.activity.member")
|
||||
a.profile-member-picture(tg-nav="user-profile:username=vm.activity.member.user.username", title="{{::vm.activity.member.user.name }}")
|
||||
img(ng-src="{{::vm.activity.member.user.photo}}", alt="{{::vm.activity.member.user.name}}")
|
||||
.activity-member-view(ng-if="::vm.timeline.has('member')")
|
||||
a.profile-member-picture(tg-nav="user-profile:username=vm.timeline.getIn(['member', 'user', 'username'])", title="{{::vm.timeline.getIn(['member', 'user', 'name'])}}")
|
||||
img(ng-src="{{::vm.timeline.getIn(['member', 'user', 'photo'])}}", alt="{{::vm.timeline.getIn(['member','user', 'name'])}}")
|
||||
.activity-member-info
|
||||
a(tg-nav="user-profile:username=vm.activity.member.user.username", title="{{::vm.activity.member.user.name }}")
|
||||
span {{::vm.activity.member.user.name}}
|
||||
p {{::vm.activity.member.role.name}}
|
||||
a(tg-nav="user-profile:username=vm.timeline.getIn(['member', 'user', 'username'])", title="{{::vm.timeline.getIn(['member','user', 'name'])}}")
|
||||
span {{::vm.timeline.getIn(['member','user', 'name'])}}
|
||||
p {{::vm.timeline.getIn(['member','role', 'name'])}}
|
||||
|
||||
div(ng-repeat="attachment in vm.activity.attachments")
|
||||
div(ng-repeat="attachment in vm.timeline.get('attachments')")
|
||||
div(tg-user-timeline-attachment="attachment")
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
a {
|
||||
a,
|
||||
.username {
|
||||
color: $primary;
|
||||
&:first-child {
|
||||
@extend %bold;
|
||||
color: $gray;
|
||||
}
|
||||
&:hover {
|
||||
color: $primary-light;
|
||||
}
|
||||
}
|
||||
a:hover {
|
||||
color: $primary-light;
|
||||
}
|
||||
blockquote {
|
||||
line-height: 1.4rem;
|
||||
|
|
|
@ -5,19 +5,37 @@ class UserTimelineService extends taiga.Service
|
|||
|
||||
constructor: (@rs, @userTimelinePaginationSequenceService) ->
|
||||
|
||||
_valid_fields: [
|
||||
'status',
|
||||
'subject',
|
||||
'description_diff',
|
||||
'assigned_to',
|
||||
'points',
|
||||
'severity',
|
||||
'priority',
|
||||
'type',
|
||||
'attachments',
|
||||
'milestone',
|
||||
'is_iocaine',
|
||||
'content_diff',
|
||||
'name',
|
||||
'estimated_finish',
|
||||
'estimated_start',
|
||||
'blocked'
|
||||
]
|
||||
|
||||
_invalid: [
|
||||
{# Items with only invalid fields
|
||||
check: (timeline) ->
|
||||
values_diff = timeline.get("data").get("values_diff")
|
||||
value_diff = timeline.get("data").get("value_diff")
|
||||
|
||||
if values_diff
|
||||
values = Object.keys(values_diff.toJS())
|
||||
if value_diff
|
||||
fieldKey = value_diff.get('key')
|
||||
|
||||
if values && values.length
|
||||
if _.every(values, (value) => @._valid_fields.indexOf(value) == -1)
|
||||
if @._valid_fields.indexOf(fieldKey) == -1
|
||||
return true
|
||||
else if values[0] == 'attachments' &&
|
||||
values_diff.get('attachments').get('new').size == 0
|
||||
else if fieldKey == 'attachments' &&
|
||||
value_diff.get('value').get('new').size == 0
|
||||
return true
|
||||
|
||||
return false
|
||||
|
@ -39,42 +57,57 @@ class UserTimelineService extends taiga.Service
|
|||
{# Task milestone
|
||||
check: (timeline) ->
|
||||
event = timeline.get('event_type').split(".")
|
||||
value_diff = timeline.get("data").get("value_diff")
|
||||
|
||||
if event[1] == "task" && event[2] == "change"
|
||||
return timeline.get("data").get("values_diff").get("milestone")
|
||||
if value_diff &&
|
||||
event[1] == "task" &&
|
||||
event[2] == "change" &&
|
||||
value_diff.get("key") == "milestone"
|
||||
return timeline.get("data").get("value_diff").get("value")
|
||||
|
||||
return false
|
||||
}
|
||||
]
|
||||
|
||||
_valid_fields: [
|
||||
'status',
|
||||
'subject',
|
||||
'description_diff',
|
||||
'assigned_to',
|
||||
'points',
|
||||
'severity',
|
||||
'priority',
|
||||
'type',
|
||||
'attachments',
|
||||
'milestone',
|
||||
'is_blocked',
|
||||
'is_iocaine',
|
||||
'content_diff',
|
||||
'name',
|
||||
'estimated_finish',
|
||||
'estimated_start'
|
||||
]
|
||||
|
||||
_isInValidTimeline: (timeline) ->
|
||||
return _.some @._invalid, (invalid) =>
|
||||
return invalid.check.call(this, timeline)
|
||||
|
||||
# create a entry per every item in the values_diff
|
||||
_splitChanges: (response) ->
|
||||
newdata = Immutable.List()
|
||||
|
||||
response.get('data').forEach (item) ->
|
||||
data = item.get('data')
|
||||
values_diff = data.get('values_diff')
|
||||
|
||||
if values_diff && values_diff.count()
|
||||
# blocked/unblocked change must be a single change
|
||||
if values_diff.has('is_blocked')
|
||||
values_diff = Immutable.Map({'blocked': values_diff})
|
||||
|
||||
values_diff.forEach (value, key) ->
|
||||
obj = Immutable.Map({
|
||||
key: key,
|
||||
value: value
|
||||
})
|
||||
|
||||
newItem = item.setIn(['data', 'value_diff'], obj)
|
||||
newItem = newItem.deleteIn(['data', 'values_diff'])
|
||||
newdata = newdata.push(newItem)
|
||||
else
|
||||
newItem = item.deleteIn(['data', 'values_diff'])
|
||||
newdata = newdata.push(newItem)
|
||||
|
||||
return response.set('data', newdata)
|
||||
|
||||
getProfileTimeline: (userId) ->
|
||||
config = {}
|
||||
|
||||
config.fetch = (page) =>
|
||||
return @rs.users.getProfileTimeline(userId, page)
|
||||
.then (response) =>
|
||||
return @._splitChanges(response)
|
||||
|
||||
config.filter = (items) =>
|
||||
return items.filterNot (item) => @._isInValidTimeline(item)
|
||||
|
@ -86,6 +119,8 @@ class UserTimelineService extends taiga.Service
|
|||
|
||||
config.fetch = (page) =>
|
||||
return @rs.users.getUserTimeline(userId, page)
|
||||
.then (response) =>
|
||||
return @._splitChanges(response)
|
||||
|
||||
config.filter = (items) =>
|
||||
return items.filterNot (item) => @._isInValidTimeline(item)
|
||||
|
@ -97,6 +132,7 @@ class UserTimelineService extends taiga.Service
|
|||
|
||||
config.fetch = (page) =>
|
||||
return @rs.projects.getTimeline(projectId, page)
|
||||
.then (response) => return @._splitChanges(response)
|
||||
|
||||
config.filter = (items) =>
|
||||
return items.filterNot (item) => @._isInValidTimeline(item)
|
||||
|
|
|
@ -7,7 +7,9 @@ describe "tgUserTimelineService", ->
|
|||
mocks.resources = {}
|
||||
|
||||
mocks.resources.users = {
|
||||
getTimeline: sinon.stub()
|
||||
getTimeline: sinon.stub(),
|
||||
getProfileTimeline: sinon.stub(),
|
||||
getUserTimeline: sinon.stub()
|
||||
}
|
||||
|
||||
mocks.resources.projects = {
|
||||
|
@ -147,73 +149,66 @@ describe "tgUserTimelineService", ->
|
|||
userId = 3
|
||||
page = 2
|
||||
|
||||
mocks.resources.users.getProfileTimeline = (_userId_) ->
|
||||
expect(_userId_).to.be.equal(userId)
|
||||
response = Immutable.fromJS({
|
||||
data: valid_items
|
||||
})
|
||||
|
||||
return Immutable.fromJS(valid_items)
|
||||
mocks.resources.users.getProfileTimeline.withArgs(userId).promise().resolve(response)
|
||||
|
||||
mocks.userTimelinePaginationSequence.generate = (config) ->
|
||||
all = config.fetch()
|
||||
expect(all.size).to.be.equal(11)
|
||||
return config.fetch().then (res) ->
|
||||
expect(res.get('data').size).to.be.equal(14)
|
||||
|
||||
items = config.filter(all).toJS()
|
||||
expect(items).to.have.length(4)
|
||||
expect(items[0]).to.be.eql(valid_items[0])
|
||||
expect(items[1]).to.be.eql(valid_items[3])
|
||||
expect(items[2]).to.be.eql(valid_items[5])
|
||||
expect(items[3]).to.be.eql(valid_items[9])
|
||||
items = config.filter(res.get('data'))
|
||||
expect(items.size).to.be.equal(5)
|
||||
|
||||
return true
|
||||
return true
|
||||
|
||||
result = userTimelineService.getProfileTimeline(userId)
|
||||
expect(result).to.be.true
|
||||
|
||||
return expect(result).to.be.eventually.true
|
||||
|
||||
it "filter invalid user timeline items", () ->
|
||||
userId = 3
|
||||
page = 2
|
||||
|
||||
mocks.resources.users.getUserTimeline = (_userId_) ->
|
||||
expect(_userId_).to.be.equal(userId)
|
||||
response = Immutable.fromJS({
|
||||
data: valid_items
|
||||
})
|
||||
|
||||
return Immutable.fromJS(valid_items)
|
||||
mocks.resources.users.getUserTimeline.withArgs(userId).promise().resolve(response)
|
||||
|
||||
mocks.userTimelinePaginationSequence.generate = (config) ->
|
||||
all = config.fetch()
|
||||
expect(all.size).to.be.equal(11)
|
||||
return config.fetch().then (res) ->
|
||||
expect(res.get('data').size).to.be.equal(14)
|
||||
|
||||
items = config.filter(all).toJS()
|
||||
expect(items).to.have.length(4)
|
||||
expect(items[0]).to.be.eql(valid_items[0])
|
||||
expect(items[1]).to.be.eql(valid_items[3])
|
||||
expect(items[2]).to.be.eql(valid_items[5])
|
||||
expect(items[3]).to.be.eql(valid_items[9])
|
||||
items = config.filter(res.get('data'))
|
||||
expect(items.size).to.be.equal(5)
|
||||
|
||||
return true
|
||||
return true
|
||||
|
||||
result = userTimelineService.getUserTimeline(userId)
|
||||
expect(result).to.be.true
|
||||
|
||||
it "filter invalid user timeline items", () ->
|
||||
return expect(result).to.be.eventually.true
|
||||
|
||||
it "filter invalid project timeline items", () ->
|
||||
userId = 3
|
||||
page = 2
|
||||
|
||||
mocks.resources.projects.getTimeline = (_userId_) ->
|
||||
expect(_userId_).to.be.equal(userId)
|
||||
response = Immutable.fromJS({
|
||||
data: valid_items
|
||||
})
|
||||
|
||||
return Immutable.fromJS(valid_items)
|
||||
mocks.resources.projects.getTimeline.withArgs(userId).promise().resolve(response)
|
||||
|
||||
mocks.userTimelinePaginationSequence.generate = (config) ->
|
||||
all = config.fetch()
|
||||
expect(all.size).to.be.equal(11)
|
||||
return config.fetch().then (res) ->
|
||||
expect(res.get('data').size).to.be.equal(14)
|
||||
|
||||
items = config.filter(all).toJS()
|
||||
expect(items).to.have.length(4)
|
||||
expect(items[0]).to.be.eql(valid_items[0])
|
||||
expect(items[1]).to.be.eql(valid_items[3])
|
||||
expect(items[2]).to.be.eql(valid_items[5])
|
||||
expect(items[3]).to.be.eql(valid_items[9])
|
||||
items = config.filter(res.get('data'))
|
||||
expect(items.size).to.be.equal(5)
|
||||
|
||||
return true
|
||||
return true
|
||||
|
||||
result = userTimelineService.getProjectTimeline(userId)
|
||||
expect(result).to.be.true
|
||||
expect(result).to.be.eventually.true
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = function(config) {
|
|||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ['mocha', 'sinon-chai'],
|
||||
frameworks: ['mocha', 'chai', 'chai-as-promised', 'sinon-chai'],
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
"author": "Kaleidos OpenSource SL",
|
||||
"license": "AGPL-3.0",
|
||||
"repository": {
|
||||
"type":"git",
|
||||
"url":"https://github.com/taigaio/taiga-front.git"
|
||||
"type": "git",
|
||||
"url": "https://github.com/taigaio/taiga-front.git"
|
||||
},
|
||||
"scripts": {
|
||||
"scss-lint": "gulp scss-lint --fail",
|
||||
|
@ -57,12 +57,10 @@
|
|||
"gulp-wrap": "^0.11.0",
|
||||
"inquirer": "^0.8.2",
|
||||
"karma": "^0.12.31",
|
||||
"karma-chai": "^0.1.0",
|
||||
"karma-chai-plugins": "^0.6.0",
|
||||
"karma-chrome-launcher": "^0.1.7",
|
||||
"karma-coffee-preprocessor": "^0.2.1",
|
||||
"karma-mocha": "^0.1.10",
|
||||
"karma-sinon": "^1.0.4",
|
||||
"karma-sinon-chai": "^0.3.0",
|
||||
"karma-sourcemap-loader": "^0.3.4",
|
||||
"minimist": "^1.1.1",
|
||||
"mocha": "^2.2.4",
|
||||
|
|
Loading…
Reference in New Issue