Merge pull request #1142 from taigaio/issue/4666/epics-pagination

epics pagination
stable
David Barragán Merino 2016-10-20 13:59:55 +02:00 committed by GitHub
commit 4d76356024
7 changed files with 138 additions and 28 deletions

View File

@ -41,6 +41,8 @@ class EpicsTableController
}
taiga.defineImmutableProperty @, 'epics', () => return @epicsService.epics
taiga.defineImmutableProperty @, 'disabledEpicsPagination', () => return @epicsService._disablePagination
taiga.defineImmutableProperty @, 'loadingEpics', () => return @epicsService._loadingEpics
toggleEpicTableOptions: () ->
@.displayOptions = !@.displayOptions
@ -50,6 +52,9 @@ class EpicsTableController
.then null, () => # on error
@confirm.notify("error")
nextPage: () ->
@epicsService.nextPage()
hoverEpicTableOption: () ->
if @.timer
@timeout.cancel(@.timer)

View File

@ -32,6 +32,7 @@ describe "EpicTable", ->
_mockTgEpicsService = () ->
mocks.tgEpicsService = {
createEpic: sinon.stub()
nextPage: sinon.stub()
}
provide.value "tgEpicsService", mocks.tgEpicsService
@ -55,3 +56,10 @@ describe "EpicTable", ->
epicTableCtrl.displayOptions = true
epicTableCtrl.toggleEpicTableOptions()
expect(epicTableCtrl.displayOptions).to.be.false
it "next page", () ->
epicTableCtrl = controller "EpicsTableCtrl"
epicTableCtrl.nextPage()
expect(mocks.tgEpicsService.nextPage).to.have.been.calledOnce

View File

@ -86,7 +86,13 @@ mixin epicSwitch(name, model)
for="switch-progress"
)
+epicSwitch('switch-progress', 'vm.column.progress')
.epics-table-body(tg-epics-sortable="vm.reorderEpic(epic, newIndex)")
.epics-table-body(
tg-epics-sortable="vm.reorderEpic(epic, newIndex)"
infinite-scroll="vm.nextPage()"
infinite-scroll-disabled="vm.disabledEpicsPagination"
infinite-scroll-immediate-check="false"
)
.epics-table-body-row(
tg-repeat="epic in vm.epics track by epic.get('id')"
tg-bind-scope
@ -95,3 +101,5 @@ mixin epicSwitch(name, model)
epic="epic"
column="vm.column"
)
div(tg-loading="vm.loadingEpics")

View File

@ -2,6 +2,15 @@
.epics-table {
margin-top: 2rem;
.loading {
margin: 2% auto;
width: 3rem;
img {
@include loading-spinner;
max-height: 3rem;
max-width: 3rem;
}
}
}
.epics-table-header {

View File

@ -28,19 +28,39 @@ class EpicsService
]
constructor: (@projectService, @attachmentsService, @resources, @xhrError) ->
@._epics = Immutable.List()
@.clear()
taiga.defineImmutableProperty @, 'epics', () => return @._epics
clear: () ->
@._loadingEpics = false
@._disablePagination = false
@._page = 1
@._epics = Immutable.List()
fetchEpics: () ->
return @resources.epics.list(@projectService.project.get('id'))
.then (epics) =>
@._epics = epics
fetchEpics: (reset = false) ->
@._loadingEpics = true
@._disablePagination = true
return @resources.epics.list(@projectService.project.get('id'), @._page)
.then (result) =>
if reset
@.clear()
@._epics = result.list
else
@._epics = @._epics.concat(result.list)
@._loadingEpics = false
@._disablePagination = !result.headers('x-pagination-next')
.catch (xhr) =>
@xhrError.response(xhr)
nextPage: () ->
@._page++
@.fetchEpics()
listRelatedUserStories: (epic) ->
return @resources.userstories.listInEpic(epic.get('id'))
@ -52,8 +72,7 @@ class EpicsService
promises = _.map attachments.toJS(), (attachment) =>
@attachmentsService.upload(attachment.file, epic.get('id'), epic.get('project'), 'epic')
Promise.all(promises).then () =>
@.fetchEpics()
Promise.all(promises).then(@.fetchEpics.bind(this, true))
reorderEpic: (epic, newIndex) ->
withoutMoved = @.epics.filter (it) => it.get('id') != epic.get('id')
@ -72,9 +91,8 @@ class EpicsService
epics_order: newOrder,
version: epic.get('version')
}
return @resources.epics.reorder(epic.get('id'), data, setOrders)
.then () =>
@.fetchEpics()
reorderRelatedUserstory: (epic, epicUserstories, userstory, newIndex) ->
withoutMoved = epicUserstories.filter (it) => it.get('id') != userstory.get('id')
@ -98,6 +116,13 @@ class EpicsService
.then () =>
return @.listRelatedUserStories(epic)
replaceEpic: (epic) ->
@._epics = @._epics.map (it) ->
if it.get('id') == epic.get('id')
return epic
return it
updateEpicStatus: (epic, statusId) ->
data = {
status: statusId,
@ -105,8 +130,7 @@ class EpicsService
}
return @resources.epics.patch(epic.get('id'), data)
.then () =>
@.fetchEpics()
.then(@.replaceEpic.bind(this))
updateEpicAssignedTo: (epic, userId) ->
data = {
@ -115,7 +139,6 @@ class EpicsService
}
return @resources.epics.patch(epic.get('id'), data)
.then () =>
@.fetchEpics()
.then(@.replaceEpic.bind(this))
angular.module('taigaEpics').service('tgEpicsService', EpicsService)

View File

@ -91,13 +91,50 @@ describe "tgEpicsService", ->
expect(epicsService._epics.size).to.be.equal(0)
it "fetch epics success", () ->
epics = Immutable.fromJS([
result = {}
result.list = Immutable.fromJS([
{ id: 111 }
{ id: 112 }
])
promise = mocks.tgResources.epics.list.withArgs(1).promise().resolve(epics)
epicsService.fetchEpics().then () ->
expect(epicsService.epics).to.be.equal(epics)
result.headers = () -> true
promise = mocks.tgResources.epics.list.withArgs(1).promise()
fetchPromise = epicsService.fetchEpics()
expect(epicsService._loadingEpics).to.be.true
expect(epicsService._disablePagination).to.be.true
promise.resolve(result)
fetchPromise.then () ->
expect(epicsService.epics).to.be.equal(result.list)
expect(epicsService._loadingEpics).to.be.false
expect(epicsService._disablePagination).to.be.false
it "fetch epics success, last page", () ->
result = {}
result.list = Immutable.fromJS([
{ id: 111 }
{ id: 112 }
])
result.headers = () -> false
promise = mocks.tgResources.epics.list.withArgs(1).promise()
fetchPromise = epicsService.fetchEpics()
expect(epicsService._loadingEpics).to.be.true
expect(epicsService._disablePagination).to.be.true
promise.resolve(result)
fetchPromise.then () ->
expect(epicsService.epics).to.be.equal(result.list)
expect(epicsService._loadingEpics).to.be.false
expect(epicsService._disablePagination).to.be.true
it "fetch epics error", () ->
epics = Immutable.fromJS([
@ -108,6 +145,23 @@ describe "tgEpicsService", ->
epicsService.fetchEpics().then () ->
expect(mocks.tgXhrErrorService.response.withArgs(new Error("error"))).have.been.calledOnce
it "replace epic", () ->
epics = Immutable.fromJS([
{ id: 111 }
{ id: 112 }
])
epicsService._epics = epics
epic = Immutable.Map({
id: 112,
title: "title1"
})
epicsService.replaceEpic(epic)
expect(epicsService._epics.get(1)).to.be.equal(epic)
it "list related userstories", () ->
epic = Immutable.fromJS({
id: 1
@ -155,9 +209,9 @@ describe "tgEpicsService", ->
.promise()
.resolve()
epicsService.fetchEpics = sinon.stub()
epicsService.replaceEpic = sinon.stub()
epicsService.updateEpicStatus(epic, 33).then () ->
expect(epicsService.fetchEpics).have.been.calledOnce
expect(epicsService.replaceEpic).have.been.calledOnce
it "Update epic assigned to", () ->
epic = Immutable.fromJS({
@ -171,9 +225,9 @@ describe "tgEpicsService", ->
.promise()
.resolve()
epicsService.fetchEpics = sinon.stub()
epicsService.replaceEpic = sinon.stub()
epicsService.updateEpicAssignedTo(epic, 33).then () ->
expect(epicsService.fetchEpics).have.been.calledOnce
expect(epicsService.replaceEpic).have.been.calledOnce
it "reorder epic", () ->
epicsService._epics = Immutable.fromJS([
@ -199,9 +253,7 @@ describe "tgEpicsService", ->
.promise()
.resolve()
epicsService.fetchEpics = sinon.stub()
epicsService.reorderEpic(epicsService._epics.get(2), 1).then () ->
expect(epicsService.fetchEpics).have.been.calledOnce
epicsService.reorderEpic(epicsService._epics.get(2), 1)
it "reorder related userstory in epic", () ->
epic = Immutable.fromJS({

View File

@ -33,13 +33,17 @@ Resource = (urlsService, http) ->
.then (result) ->
return Immutable.fromJS(result.data)
service.list = (projectId) ->
service.list = (projectId, page=0) ->
url = urlsService.resolve("epics")
params = {project: projectId}
params = {project: projectId, page: page}
return http.get(url, params)
.then (result) -> Immutable.fromJS(result.data)
.then (result) ->
return {
list: Immutable.fromJS(result.data)
headers: result.headers
}
service.patch = (id, patch) ->
url = urlsService.resolve("epics") + "/#{id}"
@ -59,6 +63,7 @@ Resource = (urlsService, http) ->
options = {"headers": {"set-orders": JSON.stringify(setOrders)}}
return http.patch(url, data, null, options)
.then (result) -> Immutable.fromJS(result.data)
service.addRelatedUserstory = (epicId, userstoryId) ->
url = urlsService.resolve("epic-related-userstories", epicId)