Skip to content

Commit

Permalink
Feat: Add list of rebuttals (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikudouSage authored Apr 3, 2024
1 parent b1a5a90 commit 4d8c2c2
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 3 deletions.
10 changes: 10 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@
</p>
</a>
</li>
@if (!loggedInInstance.anonymous) {
<li class="nav-item">
<a routerLink="/rebuttals/my" class="nav-link">
<i class="nav-icon fas fa-comments"></i>
<p>
{{ "app.sidebar.rebuttals" | transloco }}
</p>
</a>
</li>
}
<li class="nav-item" *ngIf="software === 'lemmy'">
<a routerLink="/synchronize/lemmy" class="nav-link">
<i class="nav-icon fas fa-sync"></i>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
@if (loading()) {
<app-loader />
} @else {
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">
<transloco key="app.my_rebuttals.all" [params]="{instance: currentInstance()}" />
</h3>
</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>{{'app.instance' | transloco}}</th>
<th>{{'app.reasons' | transloco}}</th>
<th>{{'app.evidence' | transloco}}</th>
<th>{{'app.rebuttal' | transloco}}</th>
<th>{{'app.actions' | transloco}}</th>
</tr>
</thead>
<tbody>
@for (instance of instances(); track instance.domain) {
<tr>
<td>
<a routerLink="/instances/detail/{{instance.domain}}">{{instance.domain}}</a>
</td>
<td>
<ul>
@if (instance.censureReasons.length) {
<li>
<strong>{{'app.censure' | transloco}}:</strong> {{instance.censureReasons.join(', ')}}
</li>
}
@if (instance.hesitationReasons.length) {
<li>
<strong>{{'app.hesitation' | transloco}}:</strong> {{instance.hesitationReasons.join(', ')}}
</li>
}
</ul>
</td>
<td>
@if (instance.censuresEvidence || instance.hesitationsEvidence) {
<ul>
@if (instance.censuresEvidence) {
<li>
<strong>{{'app.censure' | transloco}}:</strong> {{instance.censuresEvidence}}
</li>
}
@if (instance.hesitationsEvidence) {
<li>
<strong>{{'app.hesitation' | transloco}}:</strong> {{instance.hesitationsEvidence}}
</li>
}
</ul>
} @else {
<code>{{'app.not_applicable' | transloco}}</code>
}
</td>
<td>
{{instance.rebuttal}}
</td>
<td>
<button class="btn btn-danger" (click)="removeRebuttal(instance)">{{'app.generic_buttons.remove' | transloco}}</button>
&nbsp;
<a class="btn btn-primary" routerLink="/rebuttals/edit/{{instance.domain}}">{{'app.generic_buttons.edit' | transloco}}</a>
</td>
</tr>
} @empty {
<tr>
<td colspan="5">
{{'app.rebuttal.no_rebuttal_yet' | transloco}}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
min-width: 100%;
}
74 changes: 74 additions & 0 deletions src/app/rebuttals/pages/list-rebuttals/list-rebuttals.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {Component, computed, input, OnInit, signal} from '@angular/core';
import {TitleService} from "../../../services/title.service";
import {TranslatorService} from "../../../services/translator.service";
import {SharedModule} from "../../../shared/shared.module";
import {InstanceDetailResponse} from "../../../response/instance-detail.response";
import {FediseerApiService} from "../../../services/fediseer-api.service";
import {AuthenticationManagerService} from "../../../services/authentication-manager.service";
import {toPromise} from "../../../types/resolvable";
import {filter, map, zip} from "rxjs";
import {ApiResponseHelperService} from "../../../services/api-response-helper.service";
import {NormalizedInstanceDetailResponse} from "../../../response/normalized-instance-detail.response";
import {RouterLink} from "@angular/router";
import {CachedFediseerApiService} from "../../../services/cached-fediseer-api.service";

@Component({
selector: 'app-list-rebuttals',
standalone: true,
imports: [
SharedModule,
RouterLink
],
templateUrl: './list-rebuttals.component.html',
styleUrl: './list-rebuttals.component.scss'
})
export class ListRebuttalsComponent implements OnInit {
private rawInstances = signal<InstanceDetailResponse[]>([]);

public loading = signal(true);
public instances = computed(() => this.rawInstances().map(instance => NormalizedInstanceDetailResponse.fromInstanceDetail(instance)));
public currentInstance = signal(this.authManager.currentInstanceSnapshot.name);

constructor(
private readonly titleService: TitleService,
private readonly translator: TranslatorService,
private readonly api: FediseerApiService,
private readonly authManager: AuthenticationManagerService,
private readonly apiResponseHelper: ApiResponseHelperService,
private readonly cachedApi: CachedFediseerApiService,
) {
}
public async ngOnInit(): Promise<void> {
this.titleService.title = this.translator.get('app.my_rebuttals.title');
this.rawInstances.set(await toPromise(zip([
this.api.getHesitationsForInstance(this.currentInstance()),
this.api.getCensuresForInstance(this.currentInstance()),
]).pipe(
map(responses => {
if (this.apiResponseHelper.handleErrors(responses)) {
return [];
}

return responses[0].successResponse!.instances.concat(responses[1].successResponse!.instances)
.filter(instance => instance.rebuttal?.length)
}),
)));
this.loading.set(false);
}

public async removeRebuttal(instance: NormalizedInstanceDetailResponse): Promise<void> {
this.loading.set(true);
const response = await toPromise(this.api.removeRebuttal(instance.domain));
this.apiResponseHelper.handleErrors(response);

await Promise.all([
toPromise(this.cachedApi.getHesitationsForInstance(this.currentInstance(), {clear: true})),
toPromise(this.cachedApi.getCensuresForInstance(this.currentInstance(), {clear: true})),
]);
this.cachedApi.clearCensuresByInstanceCache(instance.domain);
this.cachedApi.clearHesitationsByInstanceCache(instance.domain);
this.rawInstances.update(value => [...value.filter(rawInstance => rawInstance.domain !== instance.domain)]);

this.loading.set(false);
}
}
7 changes: 6 additions & 1 deletion src/app/rebuttals/rebuttals.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ const routes: Routes = [
path: 'edit/:sourceInstance',
component: CreateEditRebuttalComponent,
canActivate: [Guards.isLoggedIn()],
}
},
{
path: 'my',
loadComponent: () => import('./pages/list-rebuttals/list-rebuttals.component').then(m => m.ListRebuttalsComponent),
canActivate: [Guards.isLoggedIn()],
},
];

@NgModule({
Expand Down
10 changes: 9 additions & 1 deletion src/app/services/api-response-helper.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ export class ApiResponseHelperService {
) {
}

public handleErrors(responses: ApiResponse<any>[], mode: MessageType = MessageType.Error): boolean {
public handleErrors(responses: ApiResponse<any>[], mode: MessageType): boolean;
public handleErrors(responses: ApiResponse<any>[]): boolean;
public handleErrors(responses: ApiResponse<any>, mode: MessageType): boolean;
public handleErrors(responses: ApiResponse<any>): boolean;

public handleErrors(responses: ApiResponse<any>[] | ApiResponse<any>, mode: MessageType = MessageType.Error): boolean {
if (!Array.isArray(responses)) {
responses = [responses];
}
let hasErrors = false;
for (const response of responses) {
if (!response.success) {
Expand Down
6 changes: 5 additions & 1 deletion src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"app.sidebar.logout": "Logout",
"app.sidebar.changelog": "Changelog",
"app.sidebar.donate": "Donate",
"app.sidebar.rebuttals": "Rebuttals",
"app.footer.created_and_maintained_by": "Created and maintained by [link:authorUrl]{{author}}[/link].",
"app.footer.created_by": "Created by [link:authorUrl]{{author}}[/link].",
"app.footer.maintained_by": "Maintained by [link:maintainerLink]{{maintainer}}[/link].",
Expand Down Expand Up @@ -130,6 +131,7 @@
"app.endorsements.my.given.unguaranteed": "No one guaranteed for this instance, you cannot endorse others.",
"app.generic_buttons.edit": "Edit",
"app.generic_buttons.cancel": "Cancel",
"app.generic_buttons.remove": "Remove",
"app.endorsements.my": "My endorsements",
"app.logo.alt": "{{fediseer}} logo",
"app.list_visibility.open": "Everyone",
Expand Down Expand Up @@ -197,5 +199,7 @@
"app.rebuttal.deleted": "Rebuttal has been successfully deleted",
"app.rebuttal.updated": "Rebuttal has been successfully updated",
"app.censure.edit": "Edit censure",
"app.hesitation.edit": "Edit hesitation"
"app.hesitation.edit": "Edit hesitation",
"app.my_rebuttals.title": "My rebuttals",
"app.my_rebuttals.all": "All rebuttals by [b]{{instance}}[/b]"
}

0 comments on commit 4d8c2c2

Please sign in to comment.