Epics in timeline
parent
e8a2155177
commit
19d0a5d0ac
|
@ -847,6 +847,8 @@
|
|||
"FILTER_TYPE_ALL_TITLE": "Show all",
|
||||
"FILTER_TYPE_PROJECTS": "Projects",
|
||||
"FILTER_TYPE_PROJECT_TITLES": "Show only projects",
|
||||
"FILTER_TYPE_EPICS": "Epics",
|
||||
"FILTER_TYPE_EPIC_TITLES": "Show only epics",
|
||||
"FILTER_TYPE_USER_STORIES": "Stories",
|
||||
"FILTER_TYPE_USER_STORIES_TITLES": "Show only user stories",
|
||||
"FILTER_TYPE_TASKS": "Tasks",
|
||||
|
@ -1202,7 +1204,8 @@
|
|||
"SPRINT_ORDER": "sprint order",
|
||||
"KANBAN_ORDER": "kanban order",
|
||||
"TASKBOARD_ORDER": "taskboard order",
|
||||
"US_ORDER": "us order"
|
||||
"US_ORDER": "us order",
|
||||
"COLOR": "color"
|
||||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
|
@ -1576,6 +1579,8 @@
|
|||
"TASK_CREATED_WITH_US": "{{username}} has created a new task {{obj_name}} in {{project_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} has created a new wiki page {{obj_name}} in {{project_name}}",
|
||||
"MILESTONE_CREATED": "{{username}} has created a new sprint {{obj_name}} in {{project_name}}",
|
||||
"EPIC_CREATED": "{{username}} has created a new epic {{obj_name}} in {{project_name}}",
|
||||
"EPIC_RELATED_USERSTORY_CREATED": "{{username}} has related the userstory {{related_us_name}} to the epic {{epic_name}} in {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} created the project {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
|
@ -1588,9 +1593,12 @@
|
|||
"TASK_UPDATED_WITH_US": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}}",
|
||||
"TASK_UPDATED_WITH_US_NEW_VALUE": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}} to {{new_value}}",
|
||||
"WIKI_UPDATED": "{{username}} has updated the wiki page {{obj_name}}",
|
||||
"EPIC_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the epic {{obj_name}}",
|
||||
"EPIC_UPDATED_WITH_NEW_VALUE": "{{username}} has updated the attribute \"{{field_name}}\" of the epic {{obj_name}} to {{new_value}}",
|
||||
"NEW_COMMENT_US": "{{username}} has commented in the US {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} has commented in the issue {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} has commented in the task {{obj_name}}",
|
||||
"NEW_COMMENT_EPIC": "{{username}} has commented in the epic {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} has a new member",
|
||||
"US_ADDED_MILESTONE": "{{username}} has added the US {{obj_name}} to {{sprint_name}}",
|
||||
"US_MOVED": "{{username}} has moved the US {{obj_name}}",
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
)
|
||||
include history-templates/history-custom-attributes
|
||||
|
||||
.diff-wrapper(
|
||||
ng-if="vm.type == 'color'"
|
||||
)
|
||||
include history-templates/history-color
|
||||
|
||||
.diff-wrapper(
|
||||
ng-if="vm.type == 'team_requirement'"
|
||||
)
|
||||
|
@ -57,5 +62,3 @@
|
|||
ng-if="vm.type == 'is_blocked'"
|
||||
)
|
||||
include history-templates/blocked
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
.diff-status-wrapper
|
||||
span.key(
|
||||
translate="ACTIVITY.FIELDS.COLOR"
|
||||
)
|
||||
span.diff(ng-if="vm.diff[0]") {{vm.diff[0]}}
|
||||
tg-svg(
|
||||
svg-icon="icon-arrow-right"
|
||||
)
|
||||
span.diff(ng-if="vm.diff[1]") {{vm.diff[1]}}
|
|
@ -24,6 +24,10 @@
|
|||
p
|
||||
span.ticket-project
|
||||
| {{:: vm.item.get('project_name') }}
|
||||
span.ticket-type(
|
||||
ng-if="::vm.item.get('type') === 'epic'"
|
||||
translate="COMMON.EPIC"
|
||||
)
|
||||
span.ticket-type(
|
||||
ng-if="::vm.item.get('type') === 'userstory'"
|
||||
translate="COMMON.USER_STORY"
|
||||
|
@ -44,6 +48,12 @@
|
|||
)
|
||||
h2
|
||||
span.ticket-id(tg-bo-ref="vm.item.get('ref')")
|
||||
a.ticket-title(
|
||||
href="#"
|
||||
ng-if="::vm.item.get('type') === 'epic'"
|
||||
tg-nav="project-epics-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')"
|
||||
title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}"
|
||||
) {{ ::vm.item.get('subject') }}
|
||||
a.ticket-title(
|
||||
href="#"
|
||||
ng-if="::vm.item.get('type') === 'userstory'"
|
||||
|
|
|
@ -28,6 +28,7 @@ class FavsBaseController
|
|||
_init: ->
|
||||
@.enableFilterByAll = true
|
||||
@.enableFilterByProjects = true
|
||||
@.enableFilterByEpics = true
|
||||
@.enableFilterByUserStories = true
|
||||
@.enableFilterByTasks = true
|
||||
@.enableFilterByIssues = true
|
||||
|
@ -101,6 +102,12 @@ class FavsBaseController
|
|||
@._resetList()
|
||||
@.loadItems()
|
||||
|
||||
showEpicsOnly: ->
|
||||
if @.type isnt "epic"
|
||||
@.type = "epic"
|
||||
@._resetList()
|
||||
@.loadItems()
|
||||
|
||||
showUserStoriesOnly: ->
|
||||
if @.type isnt "userstory"
|
||||
@.type = "userstory"
|
||||
|
@ -134,6 +141,7 @@ class ProfileLikedController extends FavsBaseController
|
|||
@.tabName = 'likes'
|
||||
@.enableFilterByAll = false
|
||||
@.enableFilterByProjects = false
|
||||
@.enableFilterByEpics = false
|
||||
@.enableFilterByUserStories = false
|
||||
@.enableFilterByTasks = false
|
||||
@.enableFilterByIssues = false
|
||||
|
@ -158,6 +166,7 @@ class ProfileVotedController extends FavsBaseController
|
|||
@.tabName = 'upvotes'
|
||||
@.enableFilterByAll = true
|
||||
@.enableFilterByProjects = false
|
||||
@.enableFilterByEpics = true
|
||||
@.enableFilterByUserStories = true
|
||||
@.enableFilterByTasks = true
|
||||
@.enableFilterByIssues = true
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# You showld have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# File: profile-favs.controller.spec.coffee
|
||||
|
@ -127,7 +127,7 @@ describe "ProfileLiked", ->
|
|||
expect(ctrl.q).to.be.equal(textQuery)
|
||||
done()
|
||||
|
||||
it "shou loading spinner during the call to the api", (done) ->
|
||||
it "show loading spinner during the call to the api", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileLiked", $scope, {user: user})
|
||||
|
||||
|
@ -154,7 +154,7 @@ describe "ProfileLiked", ->
|
|||
expect(ctrl.isLoading).to.be.false
|
||||
done()
|
||||
|
||||
it "shou no results placeholder", (done) ->
|
||||
it "show no results placeholder", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileLiked", $scope, {user: user})
|
||||
|
||||
|
@ -282,6 +282,37 @@ describe "ProfileVoted", ->
|
|||
expect(ctrl.q).to.be.equal(textQuery)
|
||||
done()
|
||||
|
||||
it "show only items of epics", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileVoted", $scope, {user: user})
|
||||
|
||||
type = "epic"
|
||||
|
||||
items = Immutable.fromJS({
|
||||
data: [
|
||||
{id: 1},
|
||||
{id: 2},
|
||||
{id: 3}
|
||||
],
|
||||
next: true
|
||||
})
|
||||
|
||||
mocks.userServices.getVoted.withArgs(user.get("id"), 1, type, null).promise().resolve(items)
|
||||
|
||||
expect(ctrl.items.size).to.be.equal(0)
|
||||
expect(ctrl.scrollDisabled).to.be.false
|
||||
expect(ctrl.type).to.be.null
|
||||
expect(ctrl.q).to.be.null
|
||||
|
||||
ctrl.showEpicsOnly().then () =>
|
||||
expectItems = items.get("data")
|
||||
|
||||
expect(ctrl.items.equals(expectItems)).to.be.true
|
||||
expect(ctrl.scrollDisabled).to.be.false
|
||||
expect(ctrl.type).to.be.type
|
||||
expect(ctrl.q).to.be.null
|
||||
done()
|
||||
|
||||
it "show only items of user stories", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileVoted", $scope, {user: user})
|
||||
|
@ -375,7 +406,7 @@ describe "ProfileVoted", ->
|
|||
expect(ctrl.q).to.be.null
|
||||
done()
|
||||
|
||||
it "shou loading spinner during the call to the api", (done) ->
|
||||
it "show loading spinner during the call to the api", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileVoted", $scope, {user: user})
|
||||
|
||||
|
@ -402,7 +433,7 @@ describe "ProfileVoted", ->
|
|||
expect(ctrl.isLoading).to.be.false
|
||||
done()
|
||||
|
||||
it "shou no results placeholder", (done) ->
|
||||
it "show no results placeholder", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileVoted", $scope, {user: user})
|
||||
|
||||
|
@ -560,6 +591,37 @@ describe "ProfileWatched", ->
|
|||
expect(ctrl.q).to.be.null
|
||||
done()
|
||||
|
||||
it "show only items of epics", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileWatched", $scope, {user: user})
|
||||
|
||||
type = "epic"
|
||||
|
||||
items = Immutable.fromJS({
|
||||
data: [
|
||||
{id: 1},
|
||||
{id: 2},
|
||||
{id: 3}
|
||||
],
|
||||
next: true
|
||||
})
|
||||
|
||||
mocks.userServices.getWatched.withArgs(user.get("id"), 1, type, null).promise().resolve(items)
|
||||
|
||||
expect(ctrl.items.size).to.be.equal(0)
|
||||
expect(ctrl.scrollDisabled).to.be.false
|
||||
expect(ctrl.type).to.be.null
|
||||
expect(ctrl.q).to.be.null
|
||||
|
||||
ctrl.showEpicsOnly().then () =>
|
||||
expectItems = items.get("data")
|
||||
|
||||
expect(ctrl.items.equals(expectItems)).to.be.true
|
||||
expect(ctrl.scrollDisabled).to.be.false
|
||||
expect(ctrl.type).to.be.type
|
||||
expect(ctrl.q).to.be.null
|
||||
done()
|
||||
|
||||
it "show only items of user stories", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileWatched", $scope, {user: user})
|
||||
|
@ -653,7 +715,7 @@ describe "ProfileWatched", ->
|
|||
expect(ctrl.q).to.be.null
|
||||
done()
|
||||
|
||||
it "shou loading spinner during the call to the api", (done) ->
|
||||
it "show loading spinner during the call to the api", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileWatched", $scope, {user: user})
|
||||
|
||||
|
@ -680,7 +742,7 @@ describe "ProfileWatched", ->
|
|||
expect(ctrl.isLoading).to.be.false
|
||||
done()
|
||||
|
||||
it "shou no results placeholder", (done) ->
|
||||
it "show no results placeholder", (done) ->
|
||||
$scope = $rootScope.$new()
|
||||
ctrl = $controller("ProfileWatched", $scope, {user: user})
|
||||
|
||||
|
|
|
@ -26,6 +26,14 @@ section.profile-favs
|
|||
title="{{ 'USER.PROFILE_FAVS.FILTER_TYPE_PROJECTS_TITLE'|translate }}"
|
||||
translate="{{ 'USER.PROFILE_FAVS.FILTER_TYPE_PROJECTS'|translate }}"
|
||||
)
|
||||
a(
|
||||
href=""
|
||||
ng-if="::vm.enableFilterByEpics"
|
||||
ng-click="vm.showEpicsOnly()"
|
||||
ng-class="{active: vm.type === 'epic'}"
|
||||
title="{{ 'USER.PROFILE_FAVS.FILTER_TYPE_EPICS_TITLE'|translate }}"
|
||||
translate="{{ 'USER.PROFILE_FAVS.FILTER_TYPE_EPICS'|translate }}"
|
||||
)
|
||||
a(
|
||||
href=""
|
||||
ng-if="::vm.enableFilterByUserStories"
|
||||
|
@ -64,6 +72,11 @@ section.profile-favs
|
|||
tg-fav-item="item"
|
||||
item-type="project"
|
||||
)
|
||||
div(
|
||||
ng-switch-when="epic"
|
||||
tg-fav-item="item"
|
||||
item-type="epic"
|
||||
)
|
||||
div(
|
||||
ng-switch-when="userstory"
|
||||
tg-fav-item="item"
|
||||
|
|
|
@ -35,7 +35,8 @@ class UserTimelineItemTitle
|
|||
'priority': 'ISSUES.FIELDS.PRIORITY',
|
||||
'type': 'ISSUES.FIELDS.TYPE',
|
||||
'is_iocaine': 'TASK.FIELDS.IS_IOCAINE',
|
||||
'is_blocked': 'COMMON.FIELDS.IS_BLOCKED'
|
||||
'is_blocked': 'COMMON.FIELDS.IS_BLOCKED',
|
||||
'color': 'COMMON.FIELDS.COLOR'
|
||||
}
|
||||
|
||||
_params: {
|
||||
|
@ -89,6 +90,18 @@ class UserTimelineItemTitle
|
|||
|
||||
return @._getLink(url, text)
|
||||
|
||||
related_us_name: (timeline, event) ->
|
||||
obj = timeline.getIn(["data", "userstory"])
|
||||
url = "project-userstories-detail:project=timeline.getIn(['data', 'userstory', 'project', 'slug']),ref=timeline.getIn(['data', 'userstory', 'ref'])"
|
||||
text = '#' + obj.get('ref') + ' ' + obj.get('subject')
|
||||
return @._getLink(url, text)
|
||||
|
||||
epic_name: (timeline, event) ->
|
||||
obj = timeline.getIn(["data", "epic"])
|
||||
url = "project-epics-detail:project=timeline.getIn(['data', 'project', 'slug']),ref=timeline.getIn(['data', 'epic', 'ref'])"
|
||||
text = '#' + obj.get('ref') + ' ' + obj.get('subject')
|
||||
return @._getLink(url, text)
|
||||
|
||||
obj_name: (timeline, event) ->
|
||||
obj = @._getTimelineObj(timeline, event)
|
||||
url = @._getDetailObjUrl(event)
|
||||
|
@ -122,9 +135,9 @@ class UserTimelineItemTitle
|
|||
"task": ["project-tasks-detail", ":project=timeline.getIn(['data', 'project', 'slug']),ref=timeline.getIn(['obj', 'ref'])"],
|
||||
"userstory": ["project-userstories-detail", ":project=timeline.getIn(['data', 'project', 'slug']),ref=timeline.getIn(['obj', 'ref'])"],
|
||||
"parent_userstory": ["project-userstories-detail", ":project=timeline.getIn(['data', 'project', 'slug']),ref=timeline.getIn(['obj', 'userstory', 'ref'])"],
|
||||
"milestone": ["project-taskboard", ":project=timeline.getIn(['data', 'project', 'slug']),sprint=timeline.getIn(['obj', 'slug'])"]
|
||||
"milestone": ["project-taskboard", ":project=timeline.getIn(['data', 'project', 'slug']),sprint=timeline.getIn(['obj', 'slug'])"],
|
||||
"epic": ["project-epics-detail", ":project=timeline.getIn(['data', 'project', 'slug']),ref=timeline.getIn(['obj', 'ref'])"]
|
||||
}
|
||||
|
||||
return url[event.obj][0] + url[event.obj][1]
|
||||
|
||||
_getLink: (url, text, title) ->
|
||||
|
@ -153,7 +166,6 @@ class UserTimelineItemTitle
|
|||
|
||||
timeline_type.translate_params.forEach (param) =>
|
||||
params[param] = @._translateTitleParams(param, timeline, event)
|
||||
|
||||
return params
|
||||
|
||||
getTitle: (timeline, event, type) ->
|
||||
|
|
|
@ -82,6 +82,18 @@ timelineType = (timeline, event) ->
|
|||
key: 'TIMELINE.MILESTONE_CREATED',
|
||||
translate_params: ['username', 'project_name', 'obj_name']
|
||||
},
|
||||
{ # NewEpic
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'epic' && event.type == 'create'
|
||||
key: 'TIMELINE.EPIC_CREATED',
|
||||
translate_params: ['username', 'project_name', 'obj_name']
|
||||
},
|
||||
{ # NewEpicRelatedUserstory
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'relateduserstory' && event.type == 'create'
|
||||
key: 'TIMELINE.EPIC_RELATED_USERSTORY_CREATED',
|
||||
translate_params: ['username', 'project_name', 'related_us_name', 'epic_name']
|
||||
},
|
||||
{ # NewUsComment
|
||||
check: (timeline, event) ->
|
||||
return timeline.getIn(['data', 'comment']) && event.obj == 'userstory'
|
||||
|
@ -109,6 +121,15 @@ timelineType = (timeline, event) ->
|
|||
text = timeline.getIn(['data', 'comment_html'])
|
||||
return $($.parseHTML(text)).text()
|
||||
},
|
||||
{ # NewEpicComment
|
||||
check: (timeline, event) ->
|
||||
return timeline.getIn(['data', 'comment']) && event.obj == 'epic'
|
||||
key: 'TIMELINE.NEW_COMMENT_EPIC'
|
||||
translate_params: ['username', 'obj_name'],
|
||||
description: (timeline) ->
|
||||
text = timeline.getIn(['data', 'comment_html'])
|
||||
return $($.parseHTML(text)).text()
|
||||
},
|
||||
{ # UsMove
|
||||
check: (timeline, event) ->
|
||||
return timeline.hasIn(['data', 'value_diff']) &&
|
||||
|
@ -258,6 +279,22 @@ timelineType = (timeline, event) ->
|
|||
key: 'TIMELINE.TASK_UPDATED_WITH_US_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'us_name', 'new_value']
|
||||
},
|
||||
{ # EpicUpdated description
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'epic' &&
|
||||
event.type == 'change' &&
|
||||
timeline.hasIn(['data', 'value_diff']) &&
|
||||
timeline.getIn(['data', 'value_diff', 'key']) == 'description_diff'
|
||||
key: 'TIMELINE.EPIC_UPDATED',
|
||||
translate_params: ['username', 'field_name', 'obj_name']
|
||||
},
|
||||
{ # EpicUpdated general
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'epic' &&
|
||||
event.type == 'change'
|
||||
key: 'TIMELINE.EPIC_UPDATED_WITH_NEW_VALUE',
|
||||
translate_params: ['username', 'field_name', 'obj_name', 'new_value']
|
||||
},
|
||||
{ # New User
|
||||
check: (timeline, event) ->
|
||||
return event.obj == 'user' && event.type == 'create'
|
||||
|
|
|
@ -47,7 +47,8 @@ class UserTimelineService extends taiga.Service
|
|||
# customs
|
||||
'blocked',
|
||||
'moveInBacklog',
|
||||
'milestone'
|
||||
'milestone',
|
||||
'color'
|
||||
]
|
||||
|
||||
_invalid: [
|
||||
|
|
Loading…
Reference in New Issue