Skip to content

Commit

Permalink
Feat: Add pagination for hesitations (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikudouSage committed Nov 8, 2023
1 parent 77cb895 commit 305d034
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class CensureInstanceComponent implements OnInit {
forkJoin([
this.cachedApi.getGuaranteesByInstance(currentInstance, {clear: true}),
this.cachedApi.getAllCensuresByInstances([currentInstance], {clear: true}),
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}),
this.cachedApi.getAllHesitationsByInstances([currentInstance], {clear: true}),
]).subscribe(() => {
this.loading = false;
this.router.navigateByUrl('/censures/my').then(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class GuaranteeInstanceComponent implements OnInit {
forkJoin([
this.cachedApi.getGuaranteesByInstance(currentInstance, {clear: true}),
this.cachedApi.getAllCensuresByInstances([currentInstance], {clear: true}),
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}),
this.cachedApi.getAllHesitationsByInstances([currentInstance], {clear: true}),
]).subscribe(() => {
this.loading = false;
this.router.navigateByUrl('/guarantees/my').then(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class EditHesitationReasonsComponent {
this.availableReasons = availableReasons;

const existing = await toPromise(
this.api.getHesitationsByInstances([this.authManager.currentInstanceSnapshot.name]).pipe(
this.api.getAllHesitationsByInstances([this.authManager.currentInstanceSnapshot.name]).pipe(
map(response => {
if (this.apiResponseHelper.handleErrors([response])) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class HesitateOnInstanceComponent implements OnInit {
forkJoin([
this.cachedApi.getGuaranteesByInstance(currentInstance, {clear: true}),
this.cachedApi.getAllCensuresByInstances([currentInstance], {clear: true}),
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}),
this.cachedApi.getAllHesitationsByInstances([currentInstance], {clear: true}),
]).subscribe(() => {
this.loading = false;
this.router.navigateByUrl('/hesitations/my').then(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class MyHesitationsComponent implements OnInit {
this.titleService.title = 'My hesitations';

const responses = await Promise.all([
toPromise(this.cachedApi.getHesitationsByInstances([this.authManager.currentInstanceSnapshot.name])),
toPromise(this.cachedApi.getAllHesitationsByInstances([this.authManager.currentInstanceSnapshot.name])),
toPromise(this.cachedApi.getCurrentInstanceInfo()),
]);

Expand All @@ -63,7 +63,7 @@ export class MyHesitationsComponent implements OnInit {
return;
}

this.cachedApi.getHesitationsByInstances([this.authManager.currentInstanceSnapshot.name], {clear: true}).subscribe();
this.cachedApi.getAllHesitationsByInstances([this.authManager.currentInstanceSnapshot.name], {clear: true}).subscribe();
this.instances = this.instances.filter(
hesitatedInstance => hesitatedInstance.domain !== instance,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ export class CensuredInstancesComponent implements OnInit {
}

private async getSourceInstances(): Promise<string[]> {
let sourceInstances = this.filterForm.controls.instances.value ?? environment.defaultCensuresListInstanceFilter;
const originalSourceInstances = this.filterForm.controls.instances.value ?? environment.defaultCensuresListInstanceFilter;
let sourceInstances = originalSourceInstances;
if (!sourceInstances.length) {
sourceInstances = environment.defaultCensuresListInstanceFilter;
}
Expand All @@ -176,7 +177,7 @@ export class CensuredInstancesComponent implements OnInit {
])];
}
if (this.filterForm.controls.includeGuaranteed.value) {
const guaranteed = await Promise.all(sourceInstances.map(async sourceInstance => {
const guaranteed = await Promise.all(originalSourceInstances.map(async sourceInstance => {
const guaranteedResponse = await toPromise(this.cachedApi.getGuaranteesByInstance(sourceInstance));
if (this.apiResponseHelper.handleErrors([guaranteedResponse])) {
this.loading = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div class="card-body">

<!-- filters -->
<form [formGroup]="filterForm" (submit)="loadInstances()">
<form [formGroup]="filterForm" (submit)="submitFilterForm()">
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
Expand Down Expand Up @@ -91,7 +91,7 @@
</tbody>
</table>
</div>
<div class="card-footer" *ngIf="maxPage > 1">
<div class="card-footer" *ngIf="maxPage > 0">
<ul class="pagination text-center">
<li class="paginate_button page-item previous" [class.disabled]="currentPage <= 1">
<a href="javascript:void(0)" class="page-link" (click)="goToPage(currentPage - 1)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ export class HesitatedInstancesComponent {

public readonly filterInstanceSpecialValueAll = FilterSpecialValueAllInstances;

private allInstances: NormalizedInstanceDetailResponse[] = [];

public instances: NormalizedInstanceDetailResponse[] = [];
public lastPageReached = false;
public currentInstance: Instance = this.authManager.currentInstanceSnapshot;
public hesitatedByMe: string[] = [];
public maxPage = 1;
Expand Down Expand Up @@ -64,7 +63,7 @@ export class HesitatedInstancesComponent {
this.titleService.title = 'Hesitated instances';

if (!this.currentInstance.anonymous) {
const response = await toPromise(this.cachedApi.getHesitationsByInstances([this.currentInstance.name]));
const response = await toPromise(this.cachedApi.getAllHesitationsByInstances([this.currentInstance.name]));
if (this.apiResponseHelper.handleErrors([response])) {
this.loading = false;
return;
Expand Down Expand Up @@ -116,7 +115,7 @@ export class HesitatedInstancesComponent {

this.activatedRoute.queryParams.subscribe(query => {
this.currentPage = query['page'] ? Number(query['page']) : 1;
this.loadPage();
this.loadInstances(false);
});
}

Expand All @@ -129,7 +128,7 @@ export class HesitatedInstancesComponent {
this.messageService.createError(`There was an api error: ${response.errorResponse!.message}`);
return;
}
this.cachedApi.getHesitationsByInstances([this.authManager.currentInstanceSnapshot.name], {clear: true}).subscribe();
this.cachedApi.getAllHesitationsByInstances([this.authManager.currentInstanceSnapshot.name], {clear: true}).subscribe();
} else {
await this.router.navigateByUrl(`/hesitations/hesitate?instance=${instance}`);
return;
Expand All @@ -152,7 +151,43 @@ export class HesitatedInstancesComponent {
public async loadInstances(redirect: boolean = true): Promise<void> {
this.loading = true;

let sourceInstances = this.filterForm.controls.instances.value ?? environment.defaultCensuresListInstanceFilter;
const response = await toPromise(this.cachedApi.getHesitationsByInstances(
await this.getSourceInstances(),
this.currentPage,
));
if (this.apiResponseHelper.handleErrors([response])) {
this.loading = false;
return;
}

for (let i = 1; i <= this.currentPage; ++i) {
if (!this.pages.includes(i)) {
this.pages.push(i);
}
}
this.instances = response.successResponse!.instances
.map(instance => NormalizedInstanceDetailResponse.fromInstanceDetail(instance));

if (!this.lastPageReached && this.instances.length === this.api.defaultPerPage && !this.pages.includes(this.currentPage + 1)) {
this.pages.push(this.currentPage + 1);
}
this.maxPage = Math.max(...this.pages);
if (this.instances.length !== this.api.defaultPerPage) {
this.lastPageReached = true;
}
if (redirect) {
await this.router.navigate([], {
relativeTo: this.activatedRoute,
queryParams: {page: 1},
queryParamsHandling: 'merge',
});
}
this.loading = false;
}

private async getSourceInstances(): Promise<string[]> {
const originalSourceInstances = this.filterForm.controls.instances.value ?? environment.defaultCensuresListInstanceFilter;
let sourceInstances = originalSourceInstances;
if (!sourceInstances.length) {
sourceInstances = environment.defaultCensuresListInstanceFilter;
}
Expand All @@ -165,15 +200,15 @@ export class HesitatedInstancesComponent {
const endorsedResponse = await toPromise(this.cachedApi.getEndorsementsByInstances(sourceInstances));
if (this.apiResponseHelper.handleErrors([endorsedResponse])) {
this.loading = false;
return;
return [];
}
sourceInstances = [...new Set([
...sourceInstances,
...endorsedResponse.successResponse!.instances.map(instance => instance.domain)
])];
}
if (this.filterForm.controls.includeGuaranteed.value) {
const guaranteed = await Promise.all(sourceInstances.map(async sourceInstance => {
const guaranteed = await Promise.all(originalSourceInstances.map(async sourceInstance => {
const guaranteedResponse = await toPromise(this.cachedApi.getGuaranteesByInstance(sourceInstance));
if (this.apiResponseHelper.handleErrors([guaranteedResponse])) {
this.loading = false;
Expand All @@ -192,40 +227,12 @@ export class HesitatedInstancesComponent {
}
}

const response = await toPromise(this.cachedApi.getHesitationsByInstances(sourceInstances));
if (this.apiResponseHelper.handleErrors([response])) {
this.loading = false;
return;
}
this.allInstances = response.successResponse!.instances.map(instance => NormalizedInstanceDetailResponse.fromInstanceDetail(instance))
.sort((a, b) => {
const countA = a.unmergedHesitationReasons.length;
const countB = b.unmergedHesitationReasons.length;

if (countA === countB) {
return 0;
}

return countA > countB ? -1 : 1;
});
this.titleService.title = `Hesitated instances (${this.allInstances.length})`;
this.maxPage = Math.ceil(this.allInstances.length / this.perPage);
this.pages = [];
for (let i = 1; i <= this.maxPage; ++i) {
this.pages.push(i);
}
if (redirect) {
await this.router.navigate([], {
relativeTo: this.activatedRoute,
queryParams: {page: 1},
queryParamsHandling: 'merge',
});
}
await this.loadPage();
this.loading = false;
return sourceInstances;
}

private async loadPage(): Promise<void> {
this.instances = this.allInstances.slice((this.currentPage - 1) * this.perPage, this.currentPage * this.perPage);
public async submitFilterForm() {
this.lastPageReached = false;
this.pages = [];
await this.loadInstances(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class InstanceDetailComponent implements OnInit {
toPromise(this.cachedApi.getGuaranteesByInstance(instanceDomain)),
toPromise(this.cachedApi.getInstanceInfo(instanceDomain)),
toPromise(this.api.getHesitationsForInstance(instanceDomain)),
toPromise(this.cachedApi.getHesitationsByInstances([instanceDomain])),
toPromise(this.cachedApi.getAllHesitationsByInstances([instanceDomain])),
]);
const manuallyHandleableResponse = [
responses[1],
Expand Down
19 changes: 17 additions & 2 deletions src/app/services/cached-fediseer-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,22 @@ export class CachedFediseerApiService {
this.permanentCache.clearByPrefix('api.safelist');
}

public getHesitationsByInstances(instances: string[], cacheConfig: CacheConfiguration = {}): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
public getHesitationsByInstances(instances: string[], page: int = 1, cacheConfig: CacheConfiguration = {}): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
cacheConfig.type ??= CacheType.Permanent;
cacheConfig.ttl ??= 60;

const cacheKey = `api.hesitations_by_instances${cacheConfig.ttl}.${instances.join('_')}.${page}`;
const item = this.getCacheItem<InstanceListResponse<InstanceDetailResponse>>(cacheKey, cacheConfig)!;
if (item.isHit && !cacheConfig.clear) {
return this.getSuccessResponse(item);
}

return this.api.getHesitationsByInstances(instances, page).pipe(
tap(this.storeResponse(item, cacheConfig)),
);
}

public getAllHesitationsByInstances(instances: string[], cacheConfig: CacheConfiguration = {}): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
cacheConfig.type ??= CacheType.Permanent;
cacheConfig.ttl ??= 60;

Expand All @@ -139,7 +154,7 @@ export class CachedFediseerApiService {
return this.getSuccessResponse(item);
}

return this.api.getHesitationsByInstances(instances).pipe(
return this.api.getAllHesitationsByInstances(instances).pipe(
tap(this.storeResponse(item, cacheConfig)),
);
}
Expand Down
70 changes: 67 additions & 3 deletions src/app/services/fediseer-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,33 @@ export class FediseerApiService {
}

public getAllCensuresByInstances(instances: string[]): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
return this.sendRequest(HttpMethod.Get, `censures_given/${instances.join(',')}`);
const sendRequest = (page: int): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> => this.getCensuresByInstances(instances, page);

let currentPage = 1;

return sendRequest(currentPage).pipe(
expand (response => {
if (!response.success) {
return EMPTY;
}
if (!response.successResponse!.instances.length) {
return EMPTY;
}
if (response.successResponse!.instances.length < this.defaultPerPage) {
return EMPTY;
}

return sendRequest(++currentPage);
}),
reduce((acc, value) => {
if (!value.success || !acc.success) {
return acc;
}
acc.successResponse!.instances = [...acc.successResponse!.instances, ...value.successResponse!.instances];

return acc;
}),
);
}

public getCensuresForInstance(instance: string): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
Expand Down Expand Up @@ -161,8 +187,46 @@ export class FediseerApiService {
return this.sendRequest(HttpMethod.Patch, `censures/${instance}`, body);
}

public getHesitationsByInstances(instances: string[]): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
return this.sendRequest(HttpMethod.Get, `hesitations_given/${instances.join(',')}`);
public getHesitationsByInstances(instances: string[], page: int = 1): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
const body: {[key: string]: string} = {
page: String(page),
limit: String(this.defaultPerPage),
};
return this.sendRequest(
HttpMethod.Get,
`hesitations_given/${instances.join(',')}`,
body,
);
}

public getAllHesitationsByInstances(instances: string[]): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
const sendRequest = (page: int): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> => this.getHesitationsByInstances(instances, page);

let currentPage = 1;

return sendRequest(currentPage).pipe(
expand (response => {
if (!response.success) {
return EMPTY;
}
if (!response.successResponse!.instances.length) {
return EMPTY;
}
if (response.successResponse!.instances.length < this.defaultPerPage) {
return EMPTY;
}

return sendRequest(++currentPage);
}),
reduce((acc, value) => {
if (!value.success || !acc.success) {
return acc;
}
acc.successResponse!.instances = [...acc.successResponse!.instances, ...value.successResponse!.instances];

return acc;
}),
);
}

public getHesitationsForInstance(instance: string): Observable<ApiResponse<InstanceListResponse<InstanceDetailResponse>>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class InstanceMoveToListComponent implements OnInit {
if (this.originalList === null) {
const lock = await this.lockService.acquire(`instance_move_to_list`);
const responses = await Promise.all([
toPromise(this.cachedApi.getHesitationsByInstances([myInstance])),
toPromise(this.cachedApi.getAllHesitationsByInstances([myInstance])),
toPromise(this.cachedApi.getAllCensuresByInstances([myInstance])),
toPromise(this.cachedApi.getGuaranteesByInstance(myInstance)),
toPromise(this.cachedApi.getEndorsementsByInstances([myInstance])),
Expand Down Expand Up @@ -176,7 +176,7 @@ export class InstanceMoveToListComponent implements OnInit {
const currentInstance = this.authManager.currentInstanceSnapshot.name;
this.cachedApi.getGuaranteesByInstance(currentInstance, {clear: true}).subscribe();
this.cachedApi.getAllCensuresByInstances([currentInstance], {clear: true}).subscribe();
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}).subscribe();
this.cachedApi.getAllHesitationsByInstances([currentInstance], {clear: true}).subscribe();

this.originalList = targetList;
this._instanceMoved.next({
Expand All @@ -200,7 +200,7 @@ export class InstanceMoveToListComponent implements OnInit {
break;
case InstanceList.Hesitations:
removeResult = await toPromise(this.api.cancelHesitation(this.instance));
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}).subscribe();
this.cachedApi.getAllHesitationsByInstances([currentInstance], {clear: true}).subscribe();
break;
case InstanceList.Endorsements:
removeResult = await toPromise(this.api.cancelEndorsement(this.instance));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ export class FilterFormComponent<TSettings extends SynchronizationSettings> impl
}

private async getHesitationsByInstances(instances: string[]): Promise<InstanceDetailResponse[] | null> {
const instancesResponse = await toPromise(this.cachedApi.getHesitationsByInstances(instances, {ttl: 5}));
const instancesResponse = await toPromise(this.cachedApi.getAllHesitationsByInstances(instances, {ttl: 5}));
if (this.apiResponseHelper.handleErrors([instancesResponse])) {
return null;
}
Expand Down

0 comments on commit 305d034

Please sign in to comment.