diff --git a/app/modules/profile/includes/profile-timeline.jade b/app/modules/profile/includes/profile-timeline.jade deleted file mode 100644 index 7ec2c7ee..00000000 --- a/app/modules/profile/includes/profile-timeline.jade +++ /dev/null @@ -1,3 +0,0 @@ -section.profile-timeline(ng-controller="ProfileTimeline as ctrl") - div(infinite-scroll="ctrl.loadTimeline()", infinite-scroll-distance="3", infinite-scroll-disabled='ctrl.loadingData') - div(ng-repeat="timeline in ctrl.timelineList", tg-profile-timeline-item="timeline") diff --git a/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.coffee b/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.coffee index a4079994..09da8a2f 100644 --- a/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.coffee +++ b/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.coffee @@ -21,7 +21,7 @@ class ProfileTimelineItemTitle if param == "username" user = timeline.data.user title_attr = @translate.instant('COMMON.SEE_USER_PROFILE', {username: user.username}) - url = 'user-profile:username=activity.user.username' + url = 'user-profile:username=vm.activity.user.username' return @._getLink(url, user.username, title_attr) else if param == 'field_name' @@ -30,12 +30,12 @@ class ProfileTimelineItemTitle return @translate.instant(@._fieldTranslationKey[field_name]) else if param == 'project_name' - url = 'project:project=activity.project.slug' + url = 'project:project=vm.activity.project.slug' return @._getLink(url, timeline.data.project.name) else if param == 'sprint_name' - url = 'project-taskboard:project=activity.project.slug,sprint=activity.sprint.slug' + url = 'project-taskboard:project=vm.activity.project.slug,sprint=vm.activity.sprint.slug' return @._getLink(url, timeline.data.milestone.name) diff --git a/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.spec.coffee b/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.spec.coffee index 133dde8b..f9def537 100644 --- a/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.spec.coffee +++ b/app/modules/profile/profile-timeline-item/profile-timeline-item-title.service.spec.coffee @@ -52,7 +52,7 @@ describe "tgProfileTimelineItemTitle", -> .returns('user-param') usernamelink = sinon.match ((value) -> - return value.username == 'xx' + return value.username == 'xx' ), "usernamelink" mockTranslate.instant @@ -113,7 +113,7 @@ describe "tgProfileTimelineItemTitle", -> } projectparam = sinon.match ((value) -> - return value.project_name == 'project_name' + return value.project_name == 'project_name' ), "projectparam" mockTranslate.instant @@ -141,7 +141,7 @@ describe "tgProfileTimelineItemTitle", -> } milestoneparam = sinon.match ((value) -> - return value.sprint_name == 'milestone_name' + return value.sprint_name == 'milestone_name' ), "milestoneparam" mockTranslate.instant diff --git a/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.coffee b/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.coffee index e0cf1141..7ab2901c 100644 --- a/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.coffee +++ b/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.coffee @@ -1,31 +1,33 @@ class ProfileTimelineItemController @.$inject = [ - "$scope", "$sce", "tgProfileTimelineItemType", "tgProfileTimelineItemTitle" ] - constructor: (@scope, @sce, @profileTimelineItemType, @profileTimelineItemTitle) -> - event = @parseEventType(@scope.vm.timeline.event_type) - type = @profileTimelineItemType.getType(@scope.vm.timeline, event) + constructor: (@sce, @profileTimelineItemType, @profileTimelineItemTitle) -> + timeline = @.timeline + event = @.parseEventType(timeline.event_type) + type = @profileTimelineItemType.getType(timeline, event) @.activity = {} - @.activity.user = @scope.vm.timeline.data.user - @.activity.project = @scope.vm.timeline.data.project - @.activity.sprint = @scope.vm.timeline.data.milestone - @.activity.title = @profileTimelineItemTitle.getTitle(@scope.vm.timeline, event, type) - @.activity.created_formated = moment(@scope.vm.timeline.created).fromNow() + @.activity.user = timeline.data.user + @.activity.project = timeline.data.project + @.activity.sprint = timeline.data.milestone + @.activity.title = @profileTimelineItemTitle.getTitle(timeline, event, type) + @.activity.created_formated = moment(timeline.created).fromNow() + #test + @.activity.obj = @.getObject(timeline, event) if type.description - @.activity.description = @sce.trustAsHtml(type.description(@scope.vm.timeline)) + @.activity.description = @sce.trustAsHtml(type.description(timeline)) if type.member - @.activity.member = type.member(@scope.vm.timeline) + @.activity.member = type.member(timeline) - if @scope.vm.timeline.data.values_diff?.attachments - @.activity.attachments = @scope.vm.timeline.data.values_diff.attachments.new + if timeline.data.values_diff?.attachments + @.activity.attachments = timeline.data.values_diff.attachments.new parseEventType: (event_type) -> event_type = event_type.split(".") @@ -36,5 +38,9 @@ class ProfileTimelineItemController type: event_type[2] } + getObject: (timeline, event) -> + if timeline.data[event.obj] + return timeline.data[event.obj] + angular.module("taigaProfile") .controller("ProfileTimelineItem", ProfileTimelineItemController) diff --git a/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.spec.coffee b/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.spec.coffee index 5f59fbd0..32edcf26 100644 --- a/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.spec.coffee +++ b/app/modules/profile/profile-timeline-item/profile-timeline-item.controller.spec.coffee @@ -72,7 +72,7 @@ describe "ProfileTimelineItemController", -> it "basic activity fields filled", () -> timeline = scope.vm.timeline - myCtrl = controller("ProfileTimelineItem", {$scope: scope}) + myCtrl = controller("ProfileTimelineItem", {$scope: scope}, {timeline: timeline}) expect(myCtrl.activity.user).to.be.equal(timeline.data.user) expect(myCtrl.activity.project).to.be.equal(timeline.data.project) @@ -94,7 +94,7 @@ describe "ProfileTimelineItemController", -> mockType.description.withArgs(timeline).returns(description) mockType.member.withArgs(timeline).returns(member) - myCtrl = controller("ProfileTimelineItem", {$scope: scope}) + myCtrl = controller("ProfileTimelineItem", {$scope: scope}, {timeline: timeline}) expect(myCtrl.activity.description).to.be.an('object') # $sce.trustAsHtml expect(myCtrl.activity.member).to.be.equal(member) diff --git a/app/modules/profile/profile-timeline-item/profile-timeline-item.jade b/app/modules/profile/profile-timeline-item/profile-timeline-item.jade index 64471945..dbf10787 100644 --- a/app/modules/profile/profile-timeline-item/profile-timeline-item.jade +++ b/app/modules/profile/profile-timeline-item/profile-timeline-item.jade @@ -14,7 +14,7 @@ div.activity-image .profile-member-picture img(ng-src="{{::vm.activity.member.user.photo}}", alt="{{::vm.activity.member.user.name}}") .activity-member-info - a(tg-nav="user-profile:username=activity.member.user.username", title="{{::vm.activity.member.user.name }}") + 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}} diff --git a/app/modules/profile/profile-timeline/profile-timeline.controller.coffee b/app/modules/profile/profile-timeline/profile-timeline.controller.coffee index 714d89ae..db97b33a 100644 --- a/app/modules/profile/profile-timeline/profile-timeline.controller.coffee +++ b/app/modules/profile/profile-timeline/profile-timeline.controller.coffee @@ -25,59 +25,26 @@ mixOf = @.taiga.mixOf class ProfileTimelineController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin) @.$inject = [ - "$tgResources", - "$tgAuth" + "$tgAuth", + "tgProfileTimelineService" ] - _valid_fields: [ - 'status', - 'subject', - 'description', - 'assigned_to', - 'points', - 'severity', - 'priority', - 'type', - 'attachments', - 'milestone', - 'is_blocked', - 'is_iocaine', - 'content_diff', - 'name', - 'estimated_finish', - 'estimated_start' - ] - - constructor: (@rs, @auth) -> - @.timelineList = [] - @.pagination = {page: 1} + constructor: (@auth, @profileTimelineService) -> + @.timelineList = Immutable.List() + @.page = 1 @.loadingData = false - _isValidField: (values) => - return _.some values, (value) => @._valid_fields.indexOf(value) != -1 - - _filterValidTimelineItems: (timeline) => - if timeline.data.values_diff - values = Object.keys(timeline.data.values_diff) - - if values && values.length - if !@._isValidField(values) - return false - else if values[0] == 'attachments' && timeline.data.values_diff.attachments.new.length == 0 - return false - - return true - loadTimeline: () -> user = @auth.getUser() @.loadingData = true - return @rs.timeline.profile(user.id, @.pagination).then (result) => - newTimelineList = _.filter result.data, @._filterValidTimelineItems - @.timelineList = @timelineList.concat(newTimelineList) - @.pagination.page++ - @.loadingData = false + @profileTimelineService + .getTimeline(user.id, @.page) + .then (newTimelineList) => + @.timelineList = @.timelineList.concat(newTimelineList) + @.page++ + @.loadingData = false angular.module("taigaProfile") .controller("ProfileTimeline", ProfileTimelineController) diff --git a/app/modules/profile/profile-timeline/profile-timeline.controller.spec.coffee b/app/modules/profile/profile-timeline/profile-timeline.controller.spec.coffee index 18669f00..954560cb 100644 --- a/app/modules/profile/profile-timeline/profile-timeline.controller.spec.coffee +++ b/app/modules/profile/profile-timeline/profile-timeline.controller.spec.coffee @@ -1,13 +1,17 @@ describe "ProfileTimelineController", -> myCtrl = scope = $q = provide = null + mocks = {} + mockUser = {id: 3} - _mockTgResources = () -> - provide.value "$tgResources", { - timeline: {} + _mockProfileTimeline = () -> + mocks.profileTimelineService = { + getTimeline: sinon.stub() } + provide.value "tgProfileTimelineService", mocks.profileTimelineService + _mockTgAuth = () -> provide.value "$tgAuth", { getUser: () -> @@ -17,7 +21,7 @@ describe "ProfileTimelineController", -> _mocks = () -> module ($provide) -> provide = $provide - _mockTgResources() + _mockProfileTimeline() _mockTgAuth() return null @@ -32,60 +36,31 @@ describe "ProfileTimelineController", -> myCtrl = $controller "ProfileTimeline" it "timelineList should be an array", () -> - expect(myCtrl.timelineList).is.an("array") - + expect(myCtrl.timelineList.toJS()).is.an("array") it "pagination starts at 1", () -> - expect(myCtrl.pagination.page).to.be.equal(1) + expect(myCtrl.page).to.be.equal(1) describe "load timeline", () -> thenStub = timelineList = null beforeEach () -> - timelineList = { - data: [ - { # valid item - data: { - values_diff: { - "status": "xx", - "subject": "xx" - } - } - }, - { # invalid item - data: { - values_diff: { - "fake": "xx" - } - } - }, - { # invalid item - data: { - values_diff: { - "fake2": "xx" - } - } - }, - { # valid item - data: { - values_diff: { - "fake2": "xx", - "milestone": "xx" - } - } - } - ] - } + timelineList = Immutable.fromJS([ + { fake: "fake"}, + { fake: "fake"}, + { fake: "fake"}, + { fake: "fake"} + ]) thenStub = sinon.stub() profileStub = sinon.stub() - .withArgs(mockUser.id, myCtrl.pagination) + .withArgs(mockUser.id, myCtrl.page) .returns({ then: thenStub }) - myCtrl.rs.timeline.profile = profileStub + mocks.profileTimelineService.getTimeline = profileStub it "the loadingData variable must be true during the timeline load", () -> expect(myCtrl.loadingData).to.be.false @@ -99,18 +74,17 @@ describe "ProfileTimelineController", -> expect(myCtrl.loadingData).to.be.false it "pagiantion increase one every call to loadTimeline", () -> - expect(myCtrl.pagination.page).to.equal(1) + expect(myCtrl.page).to.equal(1) myCtrl.loadTimeline() thenStub.callArgWith(0, timelineList) - expect(myCtrl.pagination.page).to.equal(2) + expect(myCtrl.page).to.equal(2) - it "filter the invalid timeline items", () -> + it "timeline items", () -> myCtrl.loadTimeline() thenStub.callArgWith(0, timelineList) - expect(myCtrl.timelineList[0]).to.be.equal(timelineList.data[0]) - expect(myCtrl.timelineList[1]).to.be.equal(timelineList.data[3]) + expect(myCtrl.timelineList.size).to.be.eql(4) diff --git a/app/modules/profile/profile-timeline/profile-timeline.directive.coffee b/app/modules/profile/profile-timeline/profile-timeline.directive.coffee new file mode 100644 index 00000000..ae4ba91d --- /dev/null +++ b/app/modules/profile/profile-timeline/profile-timeline.directive.coffee @@ -0,0 +1,9 @@ +ProfileTimelineDirective = -> + return { + templateUrl: "profile/profile-timeline/profile-timeline.html", + controller: "ProfileTimeline", + controllerAs: "vm", + scope: {} + } + +angular.module("taigaProfile").directive("tgProfileTimeline", ProfileTimelineDirective) diff --git a/app/modules/profile/profile-timeline/profile-timeline.jade b/app/modules/profile/profile-timeline/profile-timeline.jade new file mode 100644 index 00000000..20b6fdb5 --- /dev/null +++ b/app/modules/profile/profile-timeline/profile-timeline.jade @@ -0,0 +1,3 @@ +section.profile-timeline + div(infinite-scroll="vm.loadTimeline()", infinite-scroll-distance="3", infinite-scroll-disabled='vm.loadingData') + div(tg-repeat="timeline in vm.timelineList", tg-profile-timeline-item="timeline") diff --git a/app/modules/profile/profile-timeline/profile-timeline.service.coffee b/app/modules/profile/profile-timeline/profile-timeline.service.coffee new file mode 100644 index 00000000..0ac90906 --- /dev/null +++ b/app/modules/profile/profile-timeline/profile-timeline.service.coffee @@ -0,0 +1,51 @@ +taiga = @.taiga + +class ProfileTimelineService extends taiga.Service + @.$inject = ["$tgResources"] + + constructor: (@rs) -> + + _valid_fields: [ + 'status', + 'subject', + 'description', + 'assigned_to', + 'points', + 'severity', + 'priority', + 'type', + 'attachments', + 'milestone', + 'is_blocked', + 'is_iocaine', + 'content_diff', + 'name', + 'estimated_finish', + 'estimated_start' + ] + + _isValidField: (values) => + return _.some values, (value) => @._valid_fields.indexOf(value) != -1 + + _filterValidTimelineItems: (timeline) => + if timeline.data.values_diff + values = Object.keys(timeline.data.values_diff) + + if values && values.length + if !@._isValidField(values) + return false + else if values[0] == 'attachments' && + timeline.data.values_diff.attachments.new.length == 0 + return false + + return true + + getTimeline: (userId, page) -> + return @rs.timeline.profile(userId, page) + .then (result) => + newTimelineList = _.filter result.data, @._filterValidTimelineItems + + return Immutable.fromJS(newTimelineList) + + +angular.module("taigaProjects").service("tgProfileTimelineService", ProfileTimelineService) diff --git a/app/modules/profile/profile-timeline/profile-timeline.service.spec.coffee b/app/modules/profile/profile-timeline/profile-timeline.service.spec.coffee new file mode 100644 index 00000000..77445b3a --- /dev/null +++ b/app/modules/profile/profile-timeline/profile-timeline.service.spec.coffee @@ -0,0 +1,113 @@ +describe "tgProfileTimelineService", -> + provide = null + $q = null + $rootScope = null + profileTimelineService = null + mocks = {} + + _mockResources = () -> + mocks.resources = {} + + mocks.resources.timeline = { + profile: sinon.stub() + } + + provide.value "$tgResources", mocks.resources + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockResources() + + return null + + _setup = -> + _mocks() + + _inject = (callback) -> + inject (_tgProfileTimelineService_, _$q_, _$rootScope_) -> + profileTimelineService = _tgProfileTimelineService_ + $q = _$q_ + $rootScope = _$rootScope_ + callback() if callback + + beforeEach -> + module "taigaProjects" + _setup() + _inject() + + it "filter invalid timeline items", (done) -> + valid_items = { + data: [ + { # valid item + data: { + values_diff: { + "status": "xx", + "subject": "xx" + } + } + }, + { # invalid item + data: { + values_diff: { + "fake": "xx" + } + } + }, + { # invalid item + data: { + values_diff: { + "fake2": "xx" + } + } + }, + { # valid item + data: { + values_diff: { + "fake2": "xx", + "milestone": "xx" + } + } + }, + { # invalid item + data: { + values_diff: { + attachments: { + new: [] + } + } + } + }, + { # valid item + data: { + values_diff: { + attachments: { + new: [1, 2] + } + } + } + } + ] + } + + userId = 3 + page = 2 + + mocks.resources.timeline.profile = (_userId_, _page_) -> + expect(_userId_).to.be.equal(userId) + expect(_page_).to.be.equal(page) + + return $q (resolve, reject) -> + resolve(valid_items) + + profileTimelineService.getTimeline(userId, page) + .then (_items_) -> + items = _items_.toJS() + + expect(items[0]).to.be.eql(valid_items.data[0]) + expect(items[1]).to.be.eql(valid_items.data[3]) + expect(items[2]).to.be.eql(valid_items.data[5]) + + done() + + $rootScope.$apply() diff --git a/app/modules/profile/profile.jade b/app/modules/profile/profile.jade index 88d88eb6..9264c001 100644 --- a/app/modules/profile/profile.jade +++ b/app/modules/profile/profile.jade @@ -7,7 +7,7 @@ div.profile.centered div.content-wrapper div.content div(tg-profile-tab="activity", tab-title="Activity Tab", tab-icon="icon-timeline", tab-active) - include includes/profile-timeline + div(tg-profile-timeline) div(tg-profile-tab="projects", tab-title="Projects Tab", tab-icon="icon-project") div(tg-profile-projects)