Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
d9dd5209
Commit
d9dd5209
authored
Feb 27, 2019
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make JS pagination handle missing 'X-Total-Pages' header
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
239beb5c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
189 additions
and
37 deletions
+189
-37
app/assets/javascripts/pipelines/mixins/pipelines.js
app/assets/javascripts/pipelines/mixins/pipelines.js
+1
-5
app/assets/javascripts/vue_shared/components/table_pagination.vue
...ts/javascripts/vue_shared/components/table_pagination.vue
+17
-16
changelogs/unreleased/57991-frontend-pagination-needs-to-handle-cases-where-the-x-total-pages-header-isn-t-present.yml
...le-cases-where-the-x-total-pages-header-isn-t-present.yml
+5
-0
spec/javascripts/vue_shared/components/table_pagination_spec.js
...avascripts/vue_shared/components/table_pagination_spec.js
+166
-16
No files found.
app/assets/javascripts/pipelines/mixins/pipelines.js
View file @
d9dd5209
...
@@ -27,11 +27,7 @@ export default {
...
@@ -27,11 +27,7 @@ export default {
},
},
computed
:
{
computed
:
{
shouldRenderPagination
()
{
shouldRenderPagination
()
{
return
(
return
!
this
.
isLoading
;
!
this
.
isLoading
&&
this
.
state
.
pipelines
.
length
&&
this
.
state
.
pageInfo
.
total
>
this
.
state
.
pageInfo
.
perPage
);
},
},
},
},
beforeMount
()
{
beforeMount
()
{
...
...
app/assets/javascripts/vue_shared/components/table_pagination.vue
View file @
d9dd5209
...
@@ -54,15 +54,14 @@ export default {
...
@@ -54,15 +54,14 @@ export default {
return
this
.
pageInfo
.
nextPage
;
return
this
.
pageInfo
.
nextPage
;
},
},
getItems
()
{
getItems
()
{
const
total
=
this
.
pageInfo
.
totalPages
;
const
{
totalPages
,
nextPage
,
previousPage
,
page
}
=
this
.
pageInfo
;
const
{
page
}
=
this
.
pageInfo
;
const
items
=
[];
const
items
=
[];
if
(
page
>
1
)
{
if
(
page
>
1
)
{
items
.
push
({
title
:
FIRST
,
first
:
true
});
items
.
push
({
title
:
FIRST
,
first
:
true
});
}
}
if
(
p
age
>
1
)
{
if
(
p
reviousPage
)
{
items
.
push
({
title
:
PREV
,
prev
:
true
});
items
.
push
({
title
:
PREV
,
prev
:
true
});
}
else
{
}
else
{
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
...
@@ -70,32 +69,34 @@ export default {
...
@@ -70,32 +69,34 @@ export default {
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
if
(
totalPages
)
{
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
total
);
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
totalPages
);
for
(
let
i
=
start
;
i
<=
end
;
i
+=
1
)
{
for
(
let
i
=
start
;
i
<=
end
;
i
+=
1
)
{
const
isActive
=
i
===
page
;
const
isActive
=
i
===
page
;
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
}
}
if
(
total
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
if
(
totalPages
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
}
}
}
if
(
page
===
total
)
{
if
(
nextPage
)
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
else
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
NEXT
,
next
:
true
});
items
.
push
({
title
:
NEXT
,
next
:
true
});
}
else
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
}
if
(
total
-
page
>=
1
)
{
if
(
total
Pages
&&
totalPages
-
page
>=
1
)
{
items
.
push
({
title
:
LAST
,
last
:
true
});
items
.
push
({
title
:
LAST
,
last
:
true
});
}
}
return
items
;
return
items
;
},
},
showPagination
()
{
showPagination
()
{
return
this
.
pageInfo
.
totalPages
>
1
;
return
this
.
pageInfo
.
nextPage
||
this
.
pageInfo
.
previousPage
;
},
},
},
},
methods
:
{
methods
:
{
...
...
changelogs/unreleased/57991-frontend-pagination-needs-to-handle-cases-where-the-x-total-pages-header-isn-t-present.yml
0 → 100644
View file @
d9dd5209
---
title
:
"
Improve
the
JS
pagination
to
handle
the
case
when
the
`X-Total`
and
`X-Total-Pages`
headers
aren't
present"
merge_request
:
25601
author
:
type
:
fixed
spec/javascripts/vue_shared/components/table_pagination_spec.js
View file @
d9dd5209
...
@@ -22,10 +22,10 @@ describe('Pagination component', () => {
...
@@ -22,10 +22,10 @@ describe('Pagination component', () => {
it
(
'
should not render anything
'
,
()
=>
{
it
(
'
should not render anything
'
,
()
=>
{
component
=
mountComponent
({
component
=
mountComponent
({
pageInfo
:
{
pageInfo
:
{
nextPage
:
1
,
nextPage
:
NaN
,
page
:
1
,
page
:
1
,
perPage
:
20
,
perPage
:
20
,
previousPage
:
null
,
previousPage
:
NaN
,
total
:
15
,
total
:
15
,
totalPages
:
1
,
totalPages
:
1
,
},
},
...
@@ -58,6 +58,28 @@ describe('Pagination component', () => {
...
@@ -58,6 +58,28 @@ describe('Pagination component', () => {
expect
(
spy
).
not
.
toHaveBeenCalled
();
expect
(
spy
).
not
.
toHaveBeenCalled
();
});
});
it
(
'
should be disabled and non clickable when total and totalPages are NaN
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
2
,
page
:
1
,
perPage
:
20
,
previousPage
:
NaN
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelector
(
'
.js-previous-button
'
).
classList
.
contains
(
'
disabled
'
),
).
toEqual
(
true
);
component
.
$el
.
querySelector
(
'
.js-previous-button .page-link
'
).
click
();
expect
(
spy
).
not
.
toHaveBeenCalled
();
});
it
(
'
should be enabled and clickable
'
,
()
=>
{
it
(
'
should be enabled and clickable
'
,
()
=>
{
component
=
mountComponent
({
component
=
mountComponent
({
pageInfo
:
{
pageInfo
:
{
...
@@ -75,6 +97,24 @@ describe('Pagination component', () => {
...
@@ -75,6 +97,24 @@ describe('Pagination component', () => {
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
});
});
it
(
'
should be enabled and clickable when total and totalPages are NaN
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
3
,
page
:
2
,
perPage
:
20
,
previousPage
:
1
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
component
.
$el
.
querySelector
(
'
.js-previous-button .page-link
'
).
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
});
});
});
describe
(
'
first button
'
,
()
=>
{
describe
(
'
first button
'
,
()
=>
{
...
@@ -99,6 +139,28 @@ describe('Pagination component', () => {
...
@@ -99,6 +139,28 @@ describe('Pagination component', () => {
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
});
});
it
(
'
should call the change callback with the first page when total and totalPages are NaN
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
3
,
page
:
2
,
perPage
:
20
,
previousPage
:
1
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
const
button
=
component
.
$el
.
querySelector
(
'
.js-first-button .page-link
'
);
expect
(
button
.
textContent
.
trim
()).
toEqual
(
'
« First
'
);
button
.
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
1
);
});
});
});
describe
(
'
last button
'
,
()
=>
{
describe
(
'
last button
'
,
()
=>
{
...
@@ -123,16 +185,32 @@ describe('Pagination component', () => {
...
@@ -123,16 +185,32 @@ describe('Pagination component', () => {
expect
(
spy
).
toHaveBeenCalledWith
(
5
);
expect
(
spy
).
toHaveBeenCalledWith
(
5
);
});
});
it
(
'
should not render
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
3
,
page
:
2
,
perPage
:
20
,
previousPage
:
1
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelector
(
'
.js-last-button .page-link
'
)).
toBeNull
();
});
});
});
describe
(
'
next button
'
,
()
=>
{
describe
(
'
next button
'
,
()
=>
{
it
(
'
should be disabled and non clickable
'
,
()
=>
{
it
(
'
should be disabled and non clickable
'
,
()
=>
{
component
=
mountComponent
({
component
=
mountComponent
({
pageInfo
:
{
pageInfo
:
{
nextPage
:
5
,
nextPage
:
NaN
,
page
:
5
,
page
:
5
,
perPage
:
20
,
perPage
:
20
,
previousPage
:
1
,
previousPage
:
4
,
total
:
84
,
total
:
84
,
totalPages
:
5
,
totalPages
:
5
,
},
},
...
@@ -146,6 +224,26 @@ describe('Pagination component', () => {
...
@@ -146,6 +224,26 @@ describe('Pagination component', () => {
expect
(
spy
).
not
.
toHaveBeenCalled
();
expect
(
spy
).
not
.
toHaveBeenCalled
();
});
});
it
(
'
should be disabled and non clickable when total and totalPages are NaN
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
NaN
,
page
:
5
,
perPage
:
20
,
previousPage
:
4
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelector
(
'
.js-next-button
'
).
textContent
.
trim
()).
toEqual
(
'
Next
'
);
component
.
$el
.
querySelector
(
'
.js-next-button .page-link
'
).
click
();
expect
(
spy
).
not
.
toHaveBeenCalled
();
});
it
(
'
should be enabled and clickable
'
,
()
=>
{
it
(
'
should be enabled and clickable
'
,
()
=>
{
component
=
mountComponent
({
component
=
mountComponent
({
pageInfo
:
{
pageInfo
:
{
...
@@ -163,6 +261,24 @@ describe('Pagination component', () => {
...
@@ -163,6 +261,24 @@ describe('Pagination component', () => {
expect
(
spy
).
toHaveBeenCalledWith
(
4
);
expect
(
spy
).
toHaveBeenCalledWith
(
4
);
});
});
it
(
'
should be enabled and clickable when total and totalPages are NaN
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
4
,
page
:
3
,
perPage
:
20
,
previousPage
:
2
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
component
.
$el
.
querySelector
(
'
.js-next-button .page-link
'
).
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
4
);
});
});
});
describe
(
'
numbered buttons
'
,
()
=>
{
describe
(
'
numbered buttons
'
,
()
=>
{
...
@@ -181,22 +297,56 @@ describe('Pagination component', () => {
...
@@ -181,22 +297,56 @@ describe('Pagination component', () => {
expect
(
component
.
$el
.
querySelectorAll
(
'
.page
'
).
length
).
toEqual
(
5
);
expect
(
component
.
$el
.
querySelectorAll
(
'
.page
'
).
length
).
toEqual
(
5
);
});
});
it
(
'
should not render any page
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
4
,
page
:
3
,
perPage
:
20
,
previousPage
:
2
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelectorAll
(
'
.page
'
).
length
).
toEqual
(
0
);
});
});
});
it
(
'
should render the spread operator
'
,
()
=>
{
describe
(
'
spread operator
'
,
()
=>
{
component
=
mountComponent
({
it
(
'
should render
'
,
()
=>
{
pageInfo
:
{
component
=
mountComponent
({
nextPage
:
4
,
pageInfo
:
{
page
:
3
,
nextPage
:
4
,
perPage
:
20
,
page
:
3
,
previousPage
:
2
,
perPage
:
20
,
total
:
84
,
previousPage
:
2
,
totalPages
:
10
,
total
:
84
,
},
totalPages
:
10
,
change
:
spy
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelector
(
'
.separator
'
).
textContent
.
trim
()).
toEqual
(
'
...
'
);
});
});
expect
(
component
.
$el
.
querySelector
(
'
.separator
'
).
textContent
.
trim
()).
toEqual
(
'
...
'
);
it
(
'
should not render
'
,
()
=>
{
component
=
mountComponent
({
pageInfo
:
{
nextPage
:
4
,
page
:
3
,
perPage
:
20
,
previousPage
:
2
,
total
:
NaN
,
totalPages
:
NaN
,
},
change
:
spy
,
});
expect
(
component
.
$el
.
querySelector
(
'
.separator
'
)).
toBeNull
();
});
});
});
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment