Skip to content

Commit 752ae18

Browse files
author
Uditi Mehta
committed
Moved changes to preprints-paginated-list branch
1 parent 9330ce6 commit 752ae18

File tree

17 files changed

+364
-6
lines changed

17 files changed

+364
-6
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import Component from '@ember/component';
2+
import { action } from '@ember/object';
3+
import { inject as service } from '@ember/service';
4+
import { waitFor } from '@ember/test-waiters';
5+
import { restartableTask } from 'ember-concurrency';
6+
import { taskFor } from 'ember-concurrency-ts';
7+
8+
import Analytics from 'ember-osf-web/services/analytics';
9+
import Ready from 'ember-osf-web/services/ready';
10+
11+
export interface LoadItemsOptions {
12+
reloading: boolean;
13+
}
14+
15+
export default abstract class BaseDataComponent extends Component {
16+
// Optional arguments
17+
pageSize = 10;
18+
query?: any;
19+
20+
// Exposes a reload action the the parent scope.
21+
// Usage: `bindReload=(action (mut this.reload))`, then call `this.reload()` to trigger a reload
22+
// NOTE: Don't use this pattern too often, it could get messy. Try to reserve it for telling
23+
// data-loading components to refresh themselves.
24+
bindReload?: (action: (page?: number) => void) => void;
25+
26+
// Private properties
27+
@service ready!: Ready;
28+
@service analytics!: Analytics;
29+
30+
totalCount?: number;
31+
items?: any[];
32+
errorShown = false;
33+
page = 1;
34+
35+
async loadItemsTask(_: LoadItemsOptions) {
36+
throw new Error('Must implement loadItemsTask');
37+
}
38+
39+
@restartableTask
40+
@waitFor
41+
async loadItemsWrapperTask({ reloading }: LoadItemsOptions) {
42+
const blocker = this.ready.getBlocker();
43+
44+
try {
45+
await taskFor(this.loadItemsTask).perform({ reloading });
46+
blocker.done();
47+
} catch (e) {
48+
this.set('errorShown', true);
49+
blocker.errored(e);
50+
throw e;
51+
}
52+
}
53+
54+
didReceiveAttrs() {
55+
this.set('page', 1);
56+
if (this.bindReload) {
57+
this.bindReload(this._doReload.bind(this));
58+
}
59+
taskFor(this.loadItemsWrapperTask).perform({ reloading: false });
60+
}
61+
62+
@action
63+
_doReload(page = 1) {
64+
this.setProperties({ page });
65+
taskFor(this.loadItemsWrapperTask).perform({ reloading: true });
66+
}
67+
68+
@action
69+
next() {
70+
this.incrementProperty('page');
71+
taskFor(this.loadItemsWrapperTask).perform({ reloading: false });
72+
}
73+
74+
@action
75+
previous() {
76+
this.decrementProperty('page');
77+
taskFor(this.loadItemsWrapperTask).perform({ reloading: false });
78+
}
79+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { defineProperty } from '@ember/object';
2+
import { reads } from '@ember/object/computed';
3+
import { waitFor } from '@ember/test-waiters';
4+
import { task } from 'ember-concurrency';
5+
import { inject as service } from '@ember/service';
6+
import Store from '@ember-data/store';
7+
import { layout } from 'ember-osf-web/decorators/component';
8+
import BaseDataComponent from '../base-data-component';
9+
import template from './template';
10+
11+
@layout(template)
12+
export default class PaginatedHasMany extends BaseDataComponent {
13+
// Services
14+
@service store!: Store;
15+
16+
// Required arguments
17+
modelName!: string;
18+
19+
// Optional arguments
20+
usePlaceholders = true;
21+
22+
// Private properties
23+
@task
24+
@waitFor
25+
async loadItemsTask() {
26+
const items = await this.store.query(this.modelName, {
27+
page: this.page,
28+
'page[size]': this.pageSize,
29+
...this.query,
30+
});
31+
32+
this.setProperties({
33+
items: items.toArray(),
34+
totalCount: items.meta.total,
35+
errorShown: false,
36+
});
37+
}
38+
39+
init() {
40+
super.init();
41+
42+
defineProperty(
43+
this,
44+
'totalCount',
45+
reads('items.length'),
46+
);
47+
}
48+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{{#paginated-list/layout
2+
isTable=this.isTable
3+
items=this.items
4+
page=this.page
5+
pageSize=this.pageSize
6+
totalCount=this.totalCount
7+
loading=this.loadItemsWrapperTask.isRunning
8+
errorShown=this.errorShown
9+
next=(action this.next)
10+
previous=(action this.previous)
11+
doReload=(action this._doReload)
12+
as |list|
13+
}}
14+
{{yield list}}
15+
{{/paginated-list/layout}}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import Component from '@ember/component';
2+
import { computed } from '@ember/object';
3+
4+
import { layout, requiredAction } from 'ember-osf-web/decorators/component';
5+
6+
import template from './template';
7+
8+
@layout(template)
9+
export default class PaginatedList extends Component {
10+
// Required arguments
11+
items?: unknown[];
12+
page!: number;
13+
pageSize!: number;
14+
@requiredAction next!: () => void;
15+
@requiredAction previous!: () => void;
16+
@requiredAction doReload!: () => void;
17+
18+
// Optional arguments
19+
loading = false;
20+
errorShown = false;
21+
totalCount?: number;
22+
23+
// Private properties
24+
@computed('totalCount', 'pageSize')
25+
get maxPage() {
26+
if (typeof this.totalCount === 'undefined') {
27+
return undefined;
28+
}
29+
return Math.ceil(this.totalCount / this.pageSize);
30+
}
31+
32+
@computed('maxPage', 'page', 'pageSize', 'totalCount')
33+
get placeholderCount() {
34+
if (typeof this.maxPage === 'undefined' || typeof this.totalCount === 'undefined') {
35+
return this.pageSize / 2;
36+
}
37+
if (this.page < this.maxPage || !(this.totalCount % this.pageSize)) {
38+
return this.pageSize;
39+
}
40+
return this.totalCount % this.pageSize;
41+
}
42+
43+
@computed('items.length', 'loading', 'placeholderCount')
44+
get paginatorShown(): boolean {
45+
return Boolean((this.items && this.items.length) || (this.loading && this.placeholderCount));
46+
}
47+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.text-center {
2+
text-align: center;
3+
}
4+
5+
.m-md {
6+
margin: 15px;
7+
}
8+
9+
.list-group {
10+
padding-left: 0;
11+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{{#if this.errorShown}}
2+
<p>{{t 'osf-components.paginated-list.error'}}</p>
3+
{{else if (or @items.length (and this.loading this.placeholderCount))}}
4+
{{!-- TODO: Take a look at isTable vs list duplicated code for header and items. --}}
5+
{{#if this.isTable}}
6+
<table>
7+
{{yield (hash
8+
header=(component 'paginated-list/x-header' isTable=this.isTable)
9+
)}}
10+
<tbody>
11+
{{#if this.loading}}
12+
{{#each (range 0 this.placeholderCount)}}
13+
{{yield (hash
14+
item=(component 'paginated-list/x-item' isTable=this.isTable)
15+
doReload=(action @doReload)
16+
)}}
17+
{{/each}}
18+
{{else if @items.length}}
19+
{{#each @items as |item index|}}
20+
{{#unless item.isDeleted}}
21+
{{yield (hash
22+
item=(component 'paginated-list/x-item' isTable=this.isTable item=item index=index)
23+
doReload=(action @doReload)
24+
)}}
25+
{{/unless}}
26+
{{/each}}
27+
{{/if}}
28+
</tbody>
29+
</table>
30+
{{else}}
31+
<ul local-class='list-group m-md'>
32+
{{yield (hash header=(component 'paginated-list/x-header'))}}
33+
{{#if this.loading}}
34+
{{#each (range 0 this.placeholderCount)}}
35+
{{yield (hash
36+
item=(component 'paginated-list/x-item')
37+
doReload=(action @doReload)
38+
)}}
39+
{{/each}}
40+
{{else if @items.length}}
41+
{{#each @items as |item index|}}
42+
{{#unless item.isDeleted}}
43+
{{yield (hash
44+
item=(component 'paginated-list/x-item' item=item index=index)
45+
doReload=(action @doReload)
46+
)}}
47+
{{/unless}}
48+
{{/each}}
49+
{{/if}}
50+
</ul>
51+
{{/if}}
52+
{{#if this.paginatorShown}}
53+
<div local-class='text-center'>
54+
{{simple-paginator
55+
maxPage=this.maxPage
56+
nextPage=(action @next)
57+
previousPage=(action @previous)
58+
curPage=@page
59+
}}
60+
</div>
61+
{{/if}}
62+
{{else if this.loading}}
63+
{{loading-indicator dark=true}}
64+
{{else}}
65+
{{yield (hash
66+
empty=(component 'paginated-list/x-render')
67+
doReload=(action @doReload)
68+
)}}
69+
{{/if}}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { tagName } from '@ember-decorators/component';
2+
import Component from '@ember/component';
3+
4+
import { layout } from 'ember-osf-web/decorators/component';
5+
6+
import template from './template';
7+
8+
@layout(template)
9+
@tagName('') // No wrapping div
10+
export default class PaginatedListXHeader extends Component {
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{{#if this.isTable}}
2+
<thead ...attributes>
3+
{{yield}}
4+
</thead>
5+
{{else}}
6+
<li ...attributes>
7+
{{yield}}
8+
</li>
9+
{{/if}}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { tagName } from '@ember-decorators/component';
2+
import Component from '@ember/component';
3+
4+
import { layout } from 'ember-osf-web/decorators/component';
5+
import template from './template';
6+
7+
@layout(template)
8+
@tagName('') // No wrapping div
9+
export default class PaginatedRelationXItem extends Component {
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.list-group-item:first-child {
2+
border-top-left-radius: 4px;
3+
border-top-right-radius: 4px;
4+
}
5+
6+
.list-group-item {
7+
position: relative;
8+
display: block;
9+
padding: 10px 15px;
10+
margin-bottom: -1px;
11+
background-color: $color-bg-white;
12+
border: 1px solid $color-border-gray;
13+
}

0 commit comments

Comments
 (0)