same behavior for issues filters and backlog filters
all filter attributes are OR except tags related #2648 test with taiga-back refactoring-filter-data-APIstable
parent
5657116891
commit
74193e681f
|
@ -40,6 +40,8 @@ BacklogFiltersDirective = ($log, $location, $templates) ->
|
||||||
templateSelected = $templates.get("backlog/filter-selected.html", true)
|
templateSelected = $templates.get("backlog/filter-selected.html", true)
|
||||||
|
|
||||||
link = ($scope, $el, $attrs) ->
|
link = ($scope, $el, $attrs) ->
|
||||||
|
currentFiltersType = ''
|
||||||
|
|
||||||
$ctrl = $el.closest(".wrapper").controller()
|
$ctrl = $el.closest(".wrapper").controller()
|
||||||
selectedFilters = []
|
selectedFilters = []
|
||||||
|
|
||||||
|
@ -50,16 +52,18 @@ BacklogFiltersDirective = ($log, $location, $templates) ->
|
||||||
$el.find("h2 a.subfilter span.title").html(title)
|
$el.find("h2 a.subfilter span.title").html(title)
|
||||||
$el.find("h2 a.subfilter span.title").prop("data-type", type)
|
$el.find("h2 a.subfilter span.title").prop("data-type", type)
|
||||||
|
|
||||||
|
currentFiltersType = getFiltersType()
|
||||||
|
|
||||||
showCategories = ->
|
showCategories = ->
|
||||||
$el.find(".filters-cats").show()
|
$el.find(".filters-cats").show()
|
||||||
$el.find(".filter-list").addClass("hidden")
|
$el.find(".filter-list").addClass("hidden")
|
||||||
$el.find("h2.breadcrumb").addClass("hidden")
|
$el.find("h2.breadcrumb").addClass("hidden")
|
||||||
|
|
||||||
initializeSelectedFilters = (filters) ->
|
initializeSelectedFilters = () ->
|
||||||
showCategories()
|
showCategories()
|
||||||
selectedFilters = []
|
selectedFilters = []
|
||||||
|
|
||||||
for name, values of filters
|
for name, values of $scope.filters
|
||||||
for val in values
|
for val in values
|
||||||
selectedFilters.push(val) if val.selected
|
selectedFilters.push(val) if val.selected
|
||||||
|
|
||||||
|
@ -81,26 +85,39 @@ BacklogFiltersDirective = ($log, $location, $templates) ->
|
||||||
html = template({filters:filters})
|
html = template({filters:filters})
|
||||||
$el.find(".filter-list").html(html)
|
$el.find(".filter-list").html(html)
|
||||||
|
|
||||||
|
getFiltersType = () ->
|
||||||
|
return $el.find("h2 a.subfilter span.title").prop('data-type')
|
||||||
|
|
||||||
toggleFilterSelection = (type, id) ->
|
toggleFilterSelection = (type, id) ->
|
||||||
|
currentFiltersType = getFiltersType()
|
||||||
|
|
||||||
filters = $scope.filters[type]
|
filters = $scope.filters[type]
|
||||||
filter = _.find(filters, {id: taiga.toString(id)})
|
filter = _.find(filters, {id: id})
|
||||||
filter.selected = (not filter.selected)
|
filter.selected = (not filter.selected)
|
||||||
|
|
||||||
if filter.selected
|
if filter.selected
|
||||||
selectedFilters.push(filter)
|
selectedFilters.push(filter)
|
||||||
$scope.$apply ->
|
$scope.$apply ->
|
||||||
$ctrl.selectFilter(type, id)
|
$ctrl.selectFilter(type, id)
|
||||||
else
|
else
|
||||||
selectedFilters = _.reject(selectedFilters, filter)
|
selectedFilters = _.reject selectedFilters, (selected) ->
|
||||||
$scope.$apply ->
|
return filter.type == selected.type && filter.id == selected.id
|
||||||
$ctrl.unselectFilter(type, id)
|
|
||||||
|
$ctrl.unselectFilter(type, id)
|
||||||
|
|
||||||
renderSelectedFilters(selectedFilters)
|
renderSelectedFilters(selectedFilters)
|
||||||
|
|
||||||
currentFiltersType = $el.find("h2 a.subfilter span.title").prop('data-type')
|
|
||||||
if type == currentFiltersType
|
if type == currentFiltersType
|
||||||
renderFilters(_.reject(filters, "selected"))
|
renderFilters(_.reject(filters, "selected"))
|
||||||
|
|
||||||
$ctrl.loadUserstories()
|
$ctrl.loadUserstories()
|
||||||
|
.then () ->
|
||||||
|
# reload the tags when a tag is select or unselected
|
||||||
|
# and the filters/tags is open
|
||||||
|
if currentFiltersType == 'tags'
|
||||||
|
$ctrl.generateFilters().then () ->
|
||||||
|
tags = $scope.filters["tags"]
|
||||||
|
renderFilters(_.reject(tags, "selected"))
|
||||||
|
|
||||||
selectQFilter = debounceLeading 100, (value) ->
|
selectQFilter = debounceLeading 100, (value) ->
|
||||||
return if value is undefined
|
return if value is undefined
|
||||||
|
@ -113,11 +130,15 @@ BacklogFiltersDirective = ($log, $location, $templates) ->
|
||||||
$scope.$watch("filtersQ", selectQFilter)
|
$scope.$watch("filtersQ", selectQFilter)
|
||||||
|
|
||||||
## Angular Watchers
|
## Angular Watchers
|
||||||
$scope.$on "filters:loaded", (ctx, filters) ->
|
$scope.$on "backlog:loaded", (ctx) ->
|
||||||
initializeSelectedFilters(filters)
|
initializeSelectedFilters()
|
||||||
|
|
||||||
$scope.$on "filters:update", (ctx, filters) ->
|
$scope.$on "filters:update", (ctx) ->
|
||||||
renderFilters(filters)
|
$ctrl.generateFilters().then () ->
|
||||||
|
filters = $scope.filters[currentFiltersType]
|
||||||
|
|
||||||
|
if currentFiltersType
|
||||||
|
renderFilters(_.reject(filters, "selected"))
|
||||||
|
|
||||||
## Dom Event Handlers
|
## Dom Event Handlers
|
||||||
$el.on "click", ".filters-cats > ul > li > a", (event) ->
|
$el.on "click", ".filters-cats > ul > li > a", (event) ->
|
||||||
|
@ -126,7 +147,7 @@ BacklogFiltersDirective = ($log, $location, $templates) ->
|
||||||
tags = $scope.filters[target.data("type")]
|
tags = $scope.filters[target.data("type")]
|
||||||
|
|
||||||
renderFilters(_.reject(tags, "selected"))
|
renderFilters(_.reject(tags, "selected"))
|
||||||
showFilters(target.attr("title"), target.data("type"))
|
showFilters(target.attr("title"), target.data('type'))
|
||||||
|
|
||||||
$el.on "click", ".filters-inner > .filters-step-cat > .breadcrumb > .back", (event) ->
|
$el.on "click", ".filters-inner > .filters-step-cat > .breadcrumb > .back", (event) ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
|
@ -96,6 +96,8 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@scope.$on "usform:new:success", =>
|
@scope.$on "usform:new:success", =>
|
||||||
@.loadUserstories()
|
@.loadUserstories()
|
||||||
@.loadProjectStats()
|
@.loadProjectStats()
|
||||||
|
|
||||||
|
@rootscope.$broadcast("filters:update")
|
||||||
@analytics.trackEvent("userstory", "create", "create userstory on backlog", 1)
|
@analytics.trackEvent("userstory", "create", "create userstory on backlog", 1)
|
||||||
|
|
||||||
@scope.$on "sprintform:edit:success", =>
|
@scope.$on "sprintform:edit:success", =>
|
||||||
|
@ -105,9 +107,11 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@.loadSprints()
|
@.loadSprints()
|
||||||
@.loadProjectStats()
|
@.loadProjectStats()
|
||||||
@.loadUserstories()
|
@.loadUserstories()
|
||||||
|
@rootscope.$broadcast("filters:update")
|
||||||
|
|
||||||
@scope.$on "usform:edit:success", =>
|
@scope.$on "usform:edit:success", =>
|
||||||
@.loadUserstories()
|
@.loadUserstories()
|
||||||
|
@rootscope.$broadcast("filters:update")
|
||||||
|
|
||||||
@scope.$on("sprint:us:move", @.moveUs)
|
@scope.$on("sprint:us:move", @.moveUs)
|
||||||
@scope.$on("sprint:us:moved", @.loadSprints)
|
@scope.$on("sprint:us:moved", @.loadSprints)
|
||||||
|
@ -182,7 +186,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
|
|
||||||
resetFilters: ->
|
resetFilters: ->
|
||||||
selectedTags = _.filter(@scope.filters.tags, "selected")
|
selectedTags = _.filter(@scope.filters.tags, "selected")
|
||||||
selectedStatuses = _.filter(@scope.filters.statuses, "selected")
|
selectedStatuses = _.filter(@scope.filters.status, "selected")
|
||||||
|
|
||||||
@scope.filtersQ = ""
|
@scope.filtersQ = ""
|
||||||
|
|
||||||
|
@ -195,6 +199,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@.unselectFilter(item.type, item.id)
|
@.unselectFilter(item.type, item.id)
|
||||||
|
|
||||||
@.loadUserstories()
|
@.loadUserstories()
|
||||||
|
@rootscope.$broadcast("filters:update")
|
||||||
|
|
||||||
loadUserstories: ->
|
loadUserstories: ->
|
||||||
@scope.httpParams = @.getUrlFilters()
|
@scope.httpParams = @.getUrlFilters()
|
||||||
|
@ -208,10 +213,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@scope.userstories = _.sortBy(userstories, "backlog_order")
|
@scope.userstories = _.sortBy(userstories, "backlog_order")
|
||||||
|
|
||||||
@.setSearchDataFilters()
|
@.setSearchDataFilters()
|
||||||
@.filterVisibleUserstories()
|
|
||||||
@.generateFilters()
|
|
||||||
|
|
||||||
@rootscope.$broadcast("filters:loaded", @scope.filters)
|
|
||||||
# The broadcast must be executed when the DOM has been fully reloaded.
|
# The broadcast must be executed when the DOM has been fully reloaded.
|
||||||
# We can't assure when this exactly happens so we need a defer
|
# We can't assure when this exactly happens so we need a defer
|
||||||
scopeDefer @scope, =>
|
scopeDefer @scope, =>
|
||||||
|
@ -247,22 +249,10 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@.fillUsersAndRoles(project.members, project.roles)
|
@.fillUsersAndRoles(project.members, project.roles)
|
||||||
@.initializeSubscription()
|
@.initializeSubscription()
|
||||||
|
|
||||||
return promise.then(=> @.loadBacklog())
|
return promise
|
||||||
|
.then(=> @.loadBacklog())
|
||||||
filterVisibleUserstories: ->
|
.then(=> @.generateFilters())
|
||||||
@scope.visibleUserstories = []
|
.then(=> @scope.$emit("backlog:loaded"))
|
||||||
|
|
||||||
# Filter by tags
|
|
||||||
@scope.visibleUserstories = _.reject @scope.userstories, (us) =>
|
|
||||||
return _.some us.tags, (tag) =>
|
|
||||||
return @isFilterSelected("tag", tag)
|
|
||||||
|
|
||||||
# Filter by status
|
|
||||||
@scope.visibleUserstories = _.filter @scope.visibleUserstories, (us) =>
|
|
||||||
if @searchdata["statuses"] && Object.keys(@searchdata["statuses"]).length
|
|
||||||
return @isFilterSelected("statuses", taiga.toString(us.status))
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
prepareBulkUpdateData: (uses, field="backlog_order") ->
|
prepareBulkUpdateData: (uses, field="backlog_order") ->
|
||||||
return _.map(uses, (x) -> {"us_id": x.id, "order": x[field]})
|
return _.map(uses, (x) -> {"us_id": x.id, "order": x[field]})
|
||||||
|
@ -333,13 +323,8 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@scope.$apply =>
|
@scope.$apply =>
|
||||||
# Add new us to backlog userstories list
|
# Add new us to backlog userstories list
|
||||||
# @scope.userstories.splice(newUsIndex, 0, us)
|
# @scope.userstories.splice(newUsIndex, 0, us)
|
||||||
# @scope.visibleUserstories.splice(newUsIndex, 0, us)
|
|
||||||
args = [newUsIndex, 0].concat(usList)
|
args = [newUsIndex, 0].concat(usList)
|
||||||
Array.prototype.splice.apply(@scope.userstories, args)
|
Array.prototype.splice.apply(@scope.userstories, args)
|
||||||
Array.prototype.splice.apply(@scope.visibleUserstories, args)
|
|
||||||
|
|
||||||
# Execute the prefiltering of user stories
|
|
||||||
@.filterVisibleUserstories()
|
|
||||||
|
|
||||||
# Remove the us from the sprint list.
|
# Remove the us from the sprint list.
|
||||||
sprint = @scope.sprintsById[oldSprintId]
|
sprint = @scope.sprintsById[oldSprintId]
|
||||||
|
@ -376,8 +361,8 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
|
|
||||||
# Remove moving us from backlog userstories lists.
|
# Remove moving us from backlog userstories lists.
|
||||||
for us, key in usList
|
for us, key in usList
|
||||||
r = @scope.visibleUserstories.indexOf(us)
|
r = @scope.userstories.indexOf(us)
|
||||||
@scope.visibleUserstories.splice(r, 1)
|
@scope.userstories.splice(r, 1)
|
||||||
|
|
||||||
r = @scope.userstories.indexOf(us)
|
r = @scope.userstories.indexOf(us)
|
||||||
@scope.userstories.splice(r, 1)
|
@scope.userstories.splice(r, 1)
|
||||||
|
@ -439,74 +424,82 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@searchdata[name][val] = true
|
@searchdata[name][val] = true
|
||||||
|
|
||||||
getUrlFilters: ->
|
getUrlFilters: ->
|
||||||
return _.pick(@location.search(), "statuses", "tags", "q")
|
return _.pick(@location.search(), "status", "tags", "q")
|
||||||
|
|
||||||
generateFilters: ->
|
generateFilters: ->
|
||||||
urlfilters = @.getUrlFilters()
|
urlfilters = @.getUrlFilters()
|
||||||
@scope.filters = {}
|
@scope.filters = {}
|
||||||
|
|
||||||
#tags
|
loadFilters = {}
|
||||||
plainTags = _.flatten(_.filter(_.map(@scope.visibleUserstories, "tags")))
|
loadFilters.project = @scope.projectId
|
||||||
plainTags.sort()
|
loadFilters.tags = urlfilters.tags
|
||||||
|
|
||||||
if plainTags.length == 0 and urlfilters["tags"]
|
return @rs.userstories.filtersData(loadFilters).then (data) =>
|
||||||
plainTags.push(urlfilters["tags"])
|
choicesFiltersFormat = (choices, type, byIdObject) =>
|
||||||
|
_.map choices, (t) ->
|
||||||
|
return {
|
||||||
|
id: t[0],
|
||||||
|
name: byIdObject[t[0]].name,
|
||||||
|
color: byIdObject[t[0]].color,
|
||||||
|
count: t[1],
|
||||||
|
type: type}
|
||||||
|
|
||||||
@scope.filters.tags = _.map _.countBy(plainTags), (v, k) =>
|
tagsFilterFormat = (tags) =>
|
||||||
obj = {
|
return _.map tags, (t) =>
|
||||||
id: k,
|
return {
|
||||||
type: "tags",
|
id: t[0],
|
||||||
name: k,
|
name: t[0],
|
||||||
color: @scope.project.tags_colors[k],
|
color: @scope.project.tags_colors[t[0]],
|
||||||
count: v
|
count: t[1],
|
||||||
}
|
type: "tags"
|
||||||
obj.selected = true if @isFilterSelected("tags", obj.id)
|
}
|
||||||
return obj
|
|
||||||
|
|
||||||
selectedTags = _.filter(@scope.filters.tags, "selected")
|
# Build filters data structure
|
||||||
selectedTags = _.map(selectedTags, "name")
|
@scope.filters.status = choicesFiltersFormat(data.statuses, "status", @scope.usStatusById)
|
||||||
|
@scope.filters.tags = tagsFilterFormat(data.tags)
|
||||||
|
|
||||||
#status
|
selectedTags = _.filter(@scope.filters.tags, "selected")
|
||||||
plainStatuses = _.map(@scope.visibleUserstories, "status")
|
selectedTags = _.map(selectedTags, "id")
|
||||||
|
|
||||||
plainStatuses = _.filter plainStatuses, (status) =>
|
selectedStatuses = _.filter(@scope.filters.status, "selected")
|
||||||
if status
|
selectedStatuses = _.map(selectedStatuses, "id")
|
||||||
return status
|
|
||||||
|
|
||||||
if plainStatuses.length == 0 and urlfilters["statuses"]
|
@.markSelectedFilters(@scope.filters, urlfilters)
|
||||||
plainStatuses.push(urlfilters["statuses"])
|
|
||||||
|
|
||||||
@scope.filters.statuses = _.map _.countBy(plainStatuses), (v, k) =>
|
#store query params
|
||||||
obj = {
|
@rs.userstories.storeQueryParams(@scope.projectId, {
|
||||||
id: k,
|
"status": selectedStatuses,
|
||||||
type: "statuses",
|
"tags": selectedTags,
|
||||||
name: @scope.usStatusById[k].name,
|
"project": @scope.projectId
|
||||||
color: @scope.usStatusById[k].color,
|
"milestone": null
|
||||||
count:v
|
})
|
||||||
}
|
|
||||||
obj.selected = true if @isFilterSelected("statuses", obj.id)
|
|
||||||
|
|
||||||
return obj
|
markSelectedFilters: (filters, urlfilters) ->
|
||||||
|
# Build selected filters (from url) fast lookup data structure
|
||||||
|
searchdata = {}
|
||||||
|
for name, value of _.omit(urlfilters, "page", "orderBy")
|
||||||
|
if not searchdata[name]?
|
||||||
|
searchdata[name] = {}
|
||||||
|
|
||||||
selectedStatuses = _.filter(@scope.filters.statuses, "selected")
|
for val in "#{value}".split(",")
|
||||||
selectedStatuses = _.map(selectedStatuses, "id")
|
searchdata[name][val] = true
|
||||||
|
|
||||||
#store query params
|
isSelected = (type, id) ->
|
||||||
@rs.userstories.storeQueryParams(@scope.projectId, {
|
if searchdata[type]? and searchdata[type][id]
|
||||||
"status": selectedStatuses,
|
return true
|
||||||
"tags": selectedTags,
|
return false
|
||||||
"project": @scope.projectId
|
|
||||||
"milestone": null
|
for key, value of filters
|
||||||
})
|
for obj in value
|
||||||
|
obj.selected = if isSelected(obj.type, obj.id) then true else undefined
|
||||||
|
|
||||||
## Template actions
|
## Template actions
|
||||||
|
|
||||||
updateUserStoryStatus: () ->
|
updateUserStoryStatus: () ->
|
||||||
@.setSearchDataFilters()
|
@.setSearchDataFilters()
|
||||||
@.filterVisibleUserstories()
|
@.generateFilters().then () ->
|
||||||
@.generateFilters()
|
@rootscope.$broadcast("filters:update")
|
||||||
@rootscope.$broadcast("filters:update", @scope.filters['statuses'])
|
@.loadProjectStats()
|
||||||
@.loadProjectStats()
|
|
||||||
|
|
||||||
editUserStory: (us) ->
|
editUserStory: (us) ->
|
||||||
@rootscope.$broadcast("usform:edit", us)
|
@rootscope.$broadcast("usform:edit", us)
|
||||||
|
@ -519,7 +512,6 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
@confirm.askOnDelete(title, message).then (finish) =>
|
@confirm.askOnDelete(title, message).then (finish) =>
|
||||||
# We modify the userstories in scope so the user doesn't see the removed US for a while
|
# We modify the userstories in scope so the user doesn't see the removed US for a while
|
||||||
@scope.userstories = _.without(@scope.userstories, us)
|
@scope.userstories = _.without(@scope.userstories, us)
|
||||||
@filterVisibleUserstories()
|
|
||||||
promise = @.repo.remove(us)
|
promise = @.repo.remove(us)
|
||||||
promise.then =>
|
promise.then =>
|
||||||
finish()
|
finish()
|
||||||
|
@ -560,9 +552,9 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
||||||
total_points = stats.total_points
|
total_points = stats.total_points
|
||||||
current_sum = stats.assigned_points
|
current_sum = stats.assigned_points
|
||||||
|
|
||||||
return if not $scope.visibleUserstories
|
return if not $scope.userstories
|
||||||
|
|
||||||
for us, i in $scope.visibleUserstories
|
for us, i in $scope.userstories
|
||||||
current_sum += us.total_points
|
current_sum += us.total_points
|
||||||
|
|
||||||
if current_sum > total_points
|
if current_sum > total_points
|
||||||
|
@ -603,7 +595,6 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
||||||
# Update the total of points
|
# Update the total of points
|
||||||
$scope.sprints[0].total_points += totalExtraPoints
|
$scope.sprints[0].total_points += totalExtraPoints
|
||||||
|
|
||||||
$ctrl.filterVisibleUserstories()
|
|
||||||
$repo.saveAll(selectedUss).then ->
|
$repo.saveAll(selectedUss).then ->
|
||||||
$ctrl.loadSprints()
|
$ctrl.loadSprints()
|
||||||
$ctrl.loadProjectStats()
|
$ctrl.loadProjectStats()
|
||||||
|
@ -725,7 +716,7 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
||||||
$el.find(".backlog-table-body").disableSelection()
|
$el.find(".backlog-table-body").disableSelection()
|
||||||
|
|
||||||
filters = $ctrl.getUrlFilters()
|
filters = $ctrl.getUrlFilters()
|
||||||
if filters.statuses ||
|
if filters.status ||
|
||||||
filters.tags ||
|
filters.tags ||
|
||||||
filters.q
|
filters.q
|
||||||
showHideFilter($scope, $el, $ctrl)
|
showHideFilter($scope, $el, $ctrl)
|
||||||
|
|
|
@ -83,8 +83,6 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
@scope.$on "issueform:new:success", =>
|
@scope.$on "issueform:new:success", =>
|
||||||
@analytics.trackEvent("issue", "create", "create issue on issues list", 1)
|
@analytics.trackEvent("issue", "create", "create issue on issues list", 1)
|
||||||
@.loadIssues()
|
@.loadIssues()
|
||||||
@.loadFilters()
|
|
||||||
|
|
||||||
|
|
||||||
initializeSubscription: ->
|
initializeSubscription: ->
|
||||||
routingKey = "changes.project.#{@scope.projectId}.issues"
|
routingKey = "changes.project.#{@scope.projectId}.issues"
|
||||||
|
@ -115,9 +113,10 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
return project
|
return project
|
||||||
|
|
||||||
getUrlFilters: ->
|
getUrlFilters: ->
|
||||||
filters = _.pick(@location.search(), "page", "tags", "statuses", "types",
|
filters = _.pick(@location.search(), "page", "tags", "status", "types",
|
||||||
"q", "severities", "priorities",
|
"q", "severities", "priorities",
|
||||||
"assignedTo", "createdBy", "orderBy")
|
"assignedTo", "createdBy", "orderBy")
|
||||||
|
|
||||||
filters.page = 1 if not filters.page
|
filters.page = 1 if not filters.page
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
@ -180,9 +179,13 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
@scope.filters.myFilters = myFilters
|
@scope.filters.myFilters = myFilters
|
||||||
return myFilters
|
return myFilters
|
||||||
|
|
||||||
|
loadFilters = {}
|
||||||
|
loadFilters.project = @scope.projectId
|
||||||
|
loadFilters.tags = urlfilters.tags
|
||||||
|
|
||||||
# Load default filters data
|
# Load default filters data
|
||||||
promise = promise.then =>
|
promise = promise.then =>
|
||||||
return @rs.issues.filtersData(@scope.projectId)
|
return @rs.issues.filtersData(loadFilters)
|
||||||
|
|
||||||
# Format filters and set them on scope
|
# Format filters and set them on scope
|
||||||
return promise.then (data) =>
|
return promise.then (data) =>
|
||||||
|
@ -220,16 +223,17 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build filters data structure
|
# Build filters data structure
|
||||||
@scope.filters.statuses = choicesFiltersFormat(data.statuses, "statuses", @scope.issueStatusById)
|
@scope.filters.status = choicesFiltersFormat(data.statuses, "status", @scope.issueStatusById)
|
||||||
@scope.filters.severities = choicesFiltersFormat(data.severities, "severities", @scope.severityById)
|
@scope.filters.severities = choicesFiltersFormat(data.severities, "severities", @scope.severityById)
|
||||||
@scope.filters.priorities = choicesFiltersFormat(data.priorities, "priorities", @scope.priorityById)
|
@scope.filters.priorities = choicesFiltersFormat(data.priorities, "priorities", @scope.priorityById)
|
||||||
@scope.filters.assignedTo = usersFiltersFormat(data.assigned_to, "assignedTo", "Unassigned")
|
@scope.filters.assignedTo = usersFiltersFormat(data.assigned_to, "assignedTo", "Unassigned")
|
||||||
@scope.filters.createdBy = usersFiltersFormat(data.created_by, "createdBy", "Unknown")
|
@scope.filters.createdBy = usersFiltersFormat(data.owners, "createdBy", "Unknown")
|
||||||
@scope.filters.types = choicesFiltersFormat(data.types, "types", @scope.issueTypeById)
|
@scope.filters.types = choicesFiltersFormat(data.types, "types", @scope.issueTypeById)
|
||||||
@scope.filters.tags = tagsFilterFormat(data.tags)
|
@scope.filters.tags = tagsFilterFormat(data.tags)
|
||||||
|
|
||||||
@.removeNotExistingFiltersFromUrl()
|
@.removeNotExistingFiltersFromUrl()
|
||||||
@.markSelectedFilters(@scope.filters, urlfilters)
|
@.markSelectedFilters(@scope.filters, urlfilters)
|
||||||
|
|
||||||
@rootscope.$broadcast("filters:loaded", @scope.filters)
|
@rootscope.$broadcast("filters:loaded", @scope.filters)
|
||||||
|
|
||||||
# We need to guarantee that the last petition done here is the finally used
|
# We need to guarantee that the last petition done here is the finally used
|
||||||
|
@ -257,7 +261,7 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
name = "assigned_to"
|
name = "assigned_to"
|
||||||
else if name == "createdBy"
|
else if name == "createdBy"
|
||||||
name = "owner"
|
name = "owner"
|
||||||
else if name == "statuses"
|
else if name == "status"
|
||||||
name = "status"
|
name = "status"
|
||||||
else if name == "types"
|
else if name == "types"
|
||||||
name = "type"
|
name = "type"
|
||||||
|
@ -272,14 +276,19 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
@scope.page = data.current
|
@scope.page = data.current
|
||||||
@scope.count = data.count
|
@scope.count = data.count
|
||||||
@scope.paginatedBy = data.paginatedBy
|
@scope.paginatedBy = data.paginatedBy
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
return promise
|
||||||
|
|
||||||
loadInitialData: ->
|
loadInitialData: ->
|
||||||
promise = @.loadProject()
|
promise = @.loadProject()
|
||||||
return promise.then (project) =>
|
return promise.then (project) =>
|
||||||
@.fillUsersAndRoles(project.members, project.roles)
|
@.fillUsersAndRoles(project.users, project.roles)
|
||||||
@.initializeSubscription()
|
@.initializeSubscription()
|
||||||
return @q.all([@.loadFilters(), @.loadIssues()])
|
@.loadFilters()
|
||||||
|
|
||||||
|
return @.loadIssues()
|
||||||
|
|
||||||
saveCurrentFiltersTo: (newFilter) ->
|
saveCurrentFiltersTo: (newFilter) ->
|
||||||
deferred = @q.defer()
|
deferred = @q.defer()
|
||||||
|
@ -445,6 +454,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
||||||
|
|
||||||
link = ($scope, $el, $attrs) ->
|
link = ($scope, $el, $attrs) ->
|
||||||
$ctrl = $el.closest(".wrapper").controller()
|
$ctrl = $el.closest(".wrapper").controller()
|
||||||
|
|
||||||
selectedFilters = []
|
selectedFilters = []
|
||||||
|
|
||||||
showFilters = (title, type) ->
|
showFilters = (title, type) ->
|
||||||
|
@ -506,7 +516,6 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
||||||
filters = $scope.filters[type]
|
filters = $scope.filters[type]
|
||||||
filterId = if type == 'tags' then taiga.toString(id) else id
|
filterId = if type == 'tags' then taiga.toString(id) else id
|
||||||
filter = _.find(filters, {id: filterId})
|
filter = _.find(filters, {id: filterId})
|
||||||
|
|
||||||
filter.selected = (not filter.selected)
|
filter.selected = (not filter.selected)
|
||||||
|
|
||||||
# Convert id to null as string for properly
|
# Convert id to null as string for properly
|
||||||
|
@ -515,18 +524,27 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
||||||
|
|
||||||
if filter.selected
|
if filter.selected
|
||||||
selectedFilters.push(filter)
|
selectedFilters.push(filter)
|
||||||
$scope.$apply ->
|
$ctrl.selectFilter(type, id)
|
||||||
$ctrl.selectFilter(type, id)
|
$ctrl.selectFilter("page", 1)
|
||||||
$ctrl.selectFilter("page", 1)
|
$ctrl.storeFilters()
|
||||||
$ctrl.storeFilters()
|
|
||||||
$ctrl.loadIssues()
|
|
||||||
else
|
else
|
||||||
selectedFilters = _.reject(selectedFilters, filter)
|
selectedFilters = _.reject selectedFilters, (f) ->
|
||||||
$scope.$apply ->
|
return f.id == filter.id && f.type == filter.type
|
||||||
$ctrl.unselectFilter(type, id)
|
|
||||||
$ctrl.selectFilter("page", 1)
|
$ctrl.unselectFilter(type, id)
|
||||||
$ctrl.storeFilters()
|
$ctrl.selectFilter("page", 1)
|
||||||
$ctrl.loadIssues()
|
$ctrl.storeFilters()
|
||||||
|
|
||||||
|
$ctrl.loadIssues()
|
||||||
|
.then () ->
|
||||||
|
# reload the tags when a tag is select or unselected
|
||||||
|
# and the filters/tags is open
|
||||||
|
if filter.type == 'tags'
|
||||||
|
$ctrl.loadFilters().then () ->
|
||||||
|
# re-render the tags if the tags filter is open
|
||||||
|
if currentFiltersType == 'tags'
|
||||||
|
tags = $scope.filters[filter.type]
|
||||||
|
renderFilters(_.reject(tags, "selected"))
|
||||||
|
|
||||||
renderSelectedFilters(selectedFilters)
|
renderSelectedFilters(selectedFilters)
|
||||||
|
|
||||||
|
@ -539,7 +557,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
||||||
initializeSelectedFilters(filters)
|
initializeSelectedFilters(filters)
|
||||||
|
|
||||||
$scope.$on "filters:issueupdate", (ctx, filters) ->
|
$scope.$on "filters:issueupdate", (ctx, filters) ->
|
||||||
html = template({filters:filters.statuses})
|
html = template({filters:filters.status})
|
||||||
html = $compile(html)($scope)
|
html = $compile(html)($scope)
|
||||||
$el.find(".filter-list").html(html)
|
$el.find(".filter-list").html(html)
|
||||||
|
|
||||||
|
@ -708,7 +726,7 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) ->
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
target = angular.element(event.currentTarget)
|
target = angular.element(event.currentTarget)
|
||||||
|
|
||||||
for filter in $scope.filters.statuses
|
for filter in $scope.filters.status
|
||||||
if filter.id == issue.status
|
if filter.id == issue.status
|
||||||
filter.count--
|
filter.count--
|
||||||
|
|
||||||
|
@ -720,13 +738,13 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) ->
|
||||||
$repo.save(issue).then ->
|
$repo.save(issue).then ->
|
||||||
$ctrl.loadIssues()
|
$ctrl.loadIssues()
|
||||||
|
|
||||||
for filter in $scope.filters.statuses
|
for filter in $scope.filters.status
|
||||||
if filter.id == issue.status
|
if filter.id == issue.status
|
||||||
filter.count++
|
filter.count++
|
||||||
|
|
||||||
$rootscope.$broadcast("filters:issueupdate", $scope.filters)
|
$rootscope.$broadcast("filters:issueupdate", $scope.filters)
|
||||||
|
|
||||||
for filter in $scope.filters.statuses
|
for filter in $scope.filters.status
|
||||||
if filter.id == issue.status
|
if filter.id == issue.status
|
||||||
filter.count++
|
filter.count++
|
||||||
$rootscope.$broadcast("filters:issueupdate", $scope.filters)
|
$rootscope.$broadcast("filters:issueupdate", $scope.filters)
|
||||||
|
|
|
@ -82,6 +82,7 @@ urls = {
|
||||||
"bulk-update-us-backlog-order": "/userstories/bulk_update_backlog_order"
|
"bulk-update-us-backlog-order": "/userstories/bulk_update_backlog_order"
|
||||||
"bulk-update-us-sprint-order": "/userstories/bulk_update_sprint_order"
|
"bulk-update-us-sprint-order": "/userstories/bulk_update_sprint_order"
|
||||||
"bulk-update-us-kanban-order": "/userstories/bulk_update_kanban_order"
|
"bulk-update-us-kanban-order": "/userstories/bulk_update_kanban_order"
|
||||||
|
"userstories-filters": "/userstories/filters_data"
|
||||||
|
|
||||||
# Tasks
|
# Tasks
|
||||||
"tasks": "/tasks"
|
"tasks": "/tasks"
|
||||||
|
@ -91,6 +92,7 @@ urls = {
|
||||||
# Issues
|
# Issues
|
||||||
"issues": "/issues"
|
"issues": "/issues"
|
||||||
"bulk-create-issues": "/issues/bulk_create"
|
"bulk-create-issues": "/issues/bulk_create"
|
||||||
|
"issues-filters": "/issues/filters_data"
|
||||||
|
|
||||||
# Wiki pages
|
# Wiki pages
|
||||||
"wiki": "/wiki"
|
"wiki": "/wiki"
|
||||||
|
|
|
@ -58,8 +58,8 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) ->
|
||||||
service.stats = (projectId) ->
|
service.stats = (projectId) ->
|
||||||
return $repo.queryOneRaw("projects", "#{projectId}/issues_stats")
|
return $repo.queryOneRaw("projects", "#{projectId}/issues_stats")
|
||||||
|
|
||||||
service.filtersData = (projectId) ->
|
service.filtersData = (params) ->
|
||||||
return $repo.queryOneRaw("projects", "#{projectId}/issue_filters_data")
|
return $repo.queryOneRaw("issues-filters", null, params)
|
||||||
|
|
||||||
service.listValues = (projectId, type) ->
|
service.listValues = (projectId, type) ->
|
||||||
params = {"project": projectId}
|
params = {"project": projectId}
|
||||||
|
|
|
@ -41,6 +41,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
|
||||||
service.listInAllProjects = (filters) ->
|
service.listInAllProjects = (filters) ->
|
||||||
return $repo.queryMany("userstories", filters)
|
return $repo.queryMany("userstories", filters)
|
||||||
|
|
||||||
|
service.filtersData = (params) ->
|
||||||
|
return $repo.queryOneRaw("userstories-filters", null, params)
|
||||||
|
|
||||||
service.listUnassigned = (projectId, filters) ->
|
service.listUnassigned = (projectId, filters) ->
|
||||||
params = {"project": projectId, "milestone": "null"}
|
params = {"project": projectId, "milestone": "null"}
|
||||||
params = _.extend({}, params, filters or {})
|
params = _.extend({}, params, filters or {})
|
||||||
|
|
|
@ -34,10 +34,10 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl",
|
||||||
span.text(translate="BACKLOG.TAGS.SHOW")
|
span.text(translate="BACKLOG.TAGS.SHOW")
|
||||||
include ../includes/components/addnewus
|
include ../includes/components/addnewus
|
||||||
|
|
||||||
section.backlog-table(ng-class="{'hidden': !visibleUserstories.length}")
|
section.backlog-table(ng-class="{'hidden': !userstories.length}")
|
||||||
include ../includes/modules/backlog-table
|
include ../includes/modules/backlog-table
|
||||||
|
|
||||||
div.empty.empty-backlog(ng-class="{'hidden': visibleUserstories.length}", tg-backlog-empty-sortable)
|
div.empty.empty-backlog(ng-class="{'hidden': userstories.length}", tg-backlog-empty-sortable)
|
||||||
span.icon.icon-backlog
|
span.icon.icon-backlog
|
||||||
span.title(translate="BACKLOG.EMPTY")
|
span.title(translate="BACKLOG.EMPTY")
|
||||||
a(href="", title="{{'BACKLOG.CREATE_NEW_US' | translate}}",
|
a(href="", title="{{'BACKLOG.CREATE_NEW_US' | translate}}",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
div.row.us-item-row(ng-repeat="us in visibleUserstories track by us.id", tg-bind-scope, ng-class="{blocked: us.is_blocked}", tg-class-permission="{'readonly': '!modify_us'}")
|
div.row.us-item-row(ng-repeat="us in userstories track by us.id", tg-bind-scope, ng-class="{blocked: us.is_blocked}", tg-class-permission="{'readonly': '!modify_us'}")
|
||||||
div.user-stories
|
div.user-stories
|
||||||
div.tags-block(tg-colorize-tags="us.tags", tg-colorize-tags-type="backlog")
|
div.tags-block(tg-colorize-tags="us.tags", tg-colorize-tags-type="backlog")
|
||||||
div.user-story-name
|
div.user-story-name
|
||||||
|
|
|
@ -18,7 +18,7 @@ section.filters
|
||||||
div.filters-cats
|
div.filters-cats
|
||||||
ul
|
ul
|
||||||
li
|
li
|
||||||
a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_STATUS' | translate}}", data-type="statuses")
|
a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_STATUS' | translate}}", data-type="status")
|
||||||
span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_STATUS")
|
span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_STATUS")
|
||||||
span.icon.icon-arrow-right
|
span.icon.icon-arrow-right
|
||||||
li
|
li
|
||||||
|
|
|
@ -22,7 +22,7 @@ section.filters
|
||||||
span.title(translate="ISSUES.FILTERS.CATEGORIES.TYPE")
|
span.title(translate="ISSUES.FILTERS.CATEGORIES.TYPE")
|
||||||
span.icon.icon-arrow-right
|
span.icon.icon-arrow-right
|
||||||
li
|
li
|
||||||
a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.STATUS' | translate}}", data-type="statuses")
|
a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.STATUS' | translate}}", data-type="status")
|
||||||
span.title(translate="ISSUES.FILTERS.CATEGORIES.STATUS")
|
span.title(translate="ISSUES.FILTERS.CATEGORIES.STATUS")
|
||||||
span.icon.icon-arrow-right
|
span.icon.icon-arrow-right
|
||||||
li
|
li
|
||||||
|
|
Loading…
Reference in New Issue