diff --git a/src/app/guarantees/pages/guarantee-instance/guarantee-instance.component.ts b/src/app/guarantees/pages/guarantee-instance/guarantee-instance.component.ts
index 0cb1741..e38cb8c 100644
--- a/src/app/guarantees/pages/guarantee-instance/guarantee-instance.component.ts
+++ b/src/app/guarantees/pages/guarantee-instance/guarantee-instance.component.ts
@@ -53,12 +53,11 @@ export class GuaranteeInstanceComponent implements OnInit {
this.cachedApi.getGuaranteesByInstance(currentInstance, {clear: true}),
this.cachedApi.getCensuresByInstances([currentInstance], {clear: true}),
this.cachedApi.getHesitationsByInstances([currentInstance], {clear: true}),
- this.cachedApi.getWhitelistedInstances({clear: true}),
]).subscribe(() => {
this.loading = false;
this.router.navigateByUrl('/guarantees/my').then(() => {
this.messageService.createSuccess(`${this.form.controls.instance.value} was successfully guaranteed!`);
- this.cachedApi.getWhitelistedInstances({clear: true}).subscribe();
+ this.cachedApi.clearWhitelistCache();
});
});
});
diff --git a/src/app/guarantees/pages/my-guarantees/my-guarantees.component.ts b/src/app/guarantees/pages/my-guarantees/my-guarantees.component.ts
index 0b01f36..df7fc09 100644
--- a/src/app/guarantees/pages/my-guarantees/my-guarantees.component.ts
+++ b/src/app/guarantees/pages/my-guarantees/my-guarantees.component.ts
@@ -65,7 +65,7 @@ export class MyGuaranteesComponent implements OnInit {
this.instancesGuaranteedByMe = this.instancesGuaranteedByMe.filter(
guaranteedInstance => guaranteedInstance.domain !== instance,
);
- this.cachedApi.getWhitelistedInstances({clear: true}).subscribe();
+ this.cachedApi.clearWhitelistCache();
this.cachedApi.getGuaranteesByInstance(this.instance.name).subscribe();
});
}
diff --git a/src/app/instances/pages/edit-own-instance/edit-own-instance.component.html b/src/app/instances/pages/edit-own-instance/edit-own-instance.component.html
index ca3c8c5..3900939 100644
--- a/src/app/instances/pages/edit-own-instance/edit-own-instance.component.html
+++ b/src/app/instances/pages/edit-own-instance/edit-own-instance.component.html
@@ -16,6 +16,13 @@
Instance details
+
diff --git a/src/app/instances/pages/instance-detail/instance-detail.component.scss b/src/app/instances/pages/instance-detail/instance-detail.component.scss
index 5f5d12d..5de954f 100644
--- a/src/app/instances/pages/instance-detail/instance-detail.component.scss
+++ b/src/app/instances/pages/instance-detail/instance-detail.component.scss
@@ -1,3 +1,7 @@
:host {
min-width: 100%;
}
+
+.btn-sm {
+ margin-right: 5px;
+}
diff --git a/src/app/instances/pages/instance-detail/instance-detail.component.ts b/src/app/instances/pages/instance-detail/instance-detail.component.ts
index ccdc033..00427bb 100644
--- a/src/app/instances/pages/instance-detail/instance-detail.component.ts
+++ b/src/app/instances/pages/instance-detail/instance-detail.component.ts
@@ -11,6 +11,7 @@ import {NormalizedInstanceDetailResponse} from "../../../response/normalized-ins
import {CachedFediseerApiService} from "../../../services/cached-fediseer-api.service";
import {ListVisibility} from "../../../types/list-visibility";
import {InstanceMoveEvent} from "../../../shared/components/instance-move-to-list/instance-move-to-list.component";
+import {InstanceFlag} from "../../../types/instance-flag";
@Component({
selector: 'app-instance-detail',
@@ -122,4 +123,6 @@ export class InstanceDetailComponent implements OnInit {
public async onInstanceMoved(event: InstanceMoveEvent) {
}
+
+ protected readonly InstanceFlag = InstanceFlag;
}
diff --git a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.html b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.html
index 498b95a..3ff5bcf 100644
--- a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.html
+++ b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.html
@@ -18,6 +18,7 @@
Endorsements |
Sysadmins / moderators |
+ Tags |
Instance status |
Endorsed by me? |
@@ -50,6 +51,14 @@
{{instance.moderators}}
+
+ N/A
+
+
+ {{tag}}
+
+
+ |
|
diff --git a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.scss b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.scss
index 5f5d12d..5de954f 100644
--- a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.scss
+++ b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.scss
@@ -1,3 +1,7 @@
:host {
min-width: 100%;
}
+
+.btn-sm {
+ margin-right: 5px;
+}
diff --git a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.ts b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.ts
index c70e748..3855b94 100644
--- a/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.ts
+++ b/src/app/instances/pages/whitelisted-instances/whitelisted-instances.component.ts
@@ -10,6 +10,7 @@ import {Instance} from "../../../user/instance";
import {SuccessResponse} from "../../../response/success.response";
import {ApiResponseHelperService} from "../../../services/api-response-helper.service";
import {CachedFediseerApiService} from "../../../services/cached-fediseer-api.service";
+import {WhitelistFilter} from "../../../types/whitelist-filter";
@Component({
selector: 'app-whitelisted-instances',
@@ -44,38 +45,44 @@ export class WhitelistedInstancesComponent implements OnInit {
public async ngOnInit(): Promise {
this.titleService.title = 'Whitelisted instances';
- if (!this.currentInstance.anonymous) {
- const response = await toPromise(this.cachedApi.getEndorsementsByInstances([this.currentInstance.name]));
+ this.activatedRoute.queryParams.subscribe(async queryParams => {
+ this.loading = true;
+ this.currentPage = queryParams['page'] ? Number(queryParams['page']) : 1;
+
+ const filters: WhitelistFilter = {};
+ if (queryParams['tags']) {
+ filters.tags = queryParams['tags'].split(',');
+ }
+
+ if (!this.currentInstance.anonymous) {
+ const response = await toPromise(this.cachedApi.getEndorsementsByInstances([this.currentInstance.name]));
+ if (this.apiResponseHelper.handleErrors([response])) {
+ this.loading = false;
+ return;
+ }
+ this.endorsedByMe = response.successResponse!.instances.map(instance => instance.domain);
+ }
+
+ const response = await toPromise(this.cachedApi.getWhitelistedInstances(filters));
if (this.apiResponseHelper.handleErrors([response])) {
this.loading = false;
return;
}
- this.endorsedByMe = response.successResponse!.instances.map(instance => instance.domain);
- }
+ this.allInstances = response.successResponse!.instances.sort((a, b) => {
+ if (a.endorsements === b.endorsements) {
+ return 0;
+ }
- const response = await toPromise(this.cachedApi.getWhitelistedInstances());
- if (this.apiResponseHelper.handleErrors([response])) {
- this.loading = false;
- return;
- }
- this.allInstances = response.successResponse!.instances.sort((a, b) => {
- if (a.endorsements === b.endorsements) {
- return 0;
+ return a.endorsements > b.endorsements ? -1 : 1;
+ });
+ this.titleService.title = `Whitelisted instances (${this.allInstances.length})`;
+ this.maxPage = Math.ceil(this.allInstances.length / this.perPage);
+ for (let i = 1; i <= this.maxPage; ++i) {
+ this.pages.push(i);
}
- return a.endorsements > b.endorsements ? -1 : 1;
- });
- this.titleService.title = `Whitelisted instances (${this.allInstances.length})`;
- this.maxPage = Math.ceil(this.allInstances.length / this.perPage);
- for (let i = 1; i <= this.maxPage; ++i) {
- this.pages.push(i);
- }
-
- this.loading = false;
-
- this.activatedRoute.queryParams.subscribe(query => {
- this.currentPage = query['page'] ? Number(query['page']) : 1;
this.instances = this.allInstances.slice((this.currentPage - 1) * this.perPage, this.currentPage * this.perPage);
+ this.loading = false;
});
}
diff --git a/src/app/response/instance-detail.response.ts b/src/app/response/instance-detail.response.ts
index 401440c..a9ffe6c 100644
--- a/src/app/response/instance-detail.response.ts
+++ b/src/app/response/instance-detail.response.ts
@@ -27,4 +27,5 @@ export interface InstanceDetailResponse {
visibility_hesitations?: ListVisibility;
state: InstanceStatus;
flags: {flag: InstanceFlag, comment: string}[];
+ tags: string[];
}
diff --git a/src/app/services/cached-fediseer-api.service.ts b/src/app/services/cached-fediseer-api.service.ts
index 6ae2911..bda51d8 100644
--- a/src/app/services/cached-fediseer-api.service.ts
+++ b/src/app/services/cached-fediseer-api.service.ts
@@ -1,12 +1,13 @@
import {Injectable} from '@angular/core';
import {ApiResponse, FediseerApiService} from "./fediseer-api.service";
import {RuntimeCacheService} from "./cache/runtime-cache.service";
-import {Observable, of, tap} from "rxjs";
+import {map, Observable, of, tap} from "rxjs";
import {InstanceDetailResponse} from "../response/instance-detail.response";
import {int} from "../types/number";
import {PermanentCacheService} from "./cache/permanent-cache.service";
import {Cache, CacheItem} from "./cache/cache";
import {InstanceListResponse} from "../response/instance-list.response";
+import {WhitelistFilter} from "../types/whitelist-filter";
export enum CacheType {
Runtime,
@@ -61,21 +62,26 @@ export class CachedFediseerApiService {
);
}
- public getWhitelistedInstances(cacheConfig: CacheConfiguration = {}): Observable>> {
+ public getWhitelistedInstances(whitelistFilter: WhitelistFilter = {}, cacheConfig: CacheConfiguration = {}): Observable>> {
cacheConfig.type ??= CacheType.Permanent;
cacheConfig.ttl ??= 120;
- const cacheKey = `api.whitelist${cacheConfig.ttl}`;
+ const cacheKey = `api.whitelist${cacheConfig.ttl}.${JSON.stringify(whitelistFilter)}`;
const item = this.getCacheItem>(cacheKey, cacheConfig)!;
if (item.isHit && !cacheConfig.clear) {
return this.getSuccessResponse(item);
}
- return this.api.getWhitelistedInstances().pipe(
+ return this.api.getWhitelistedInstances(whitelistFilter).pipe(
tap(this.storeResponse(item, cacheConfig)),
);
}
+ public clearWhitelistCache(): void {
+ this.runtimeCache.clearByPrefix('api.whitelist');
+ this.permanentCache.clearByPrefix('api.whitelist');
+ }
+
public getHesitationsByInstances(instances: string[], cacheConfig: CacheConfiguration = {}): Observable>> {
cacheConfig.type ??= CacheType.Permanent;
cacheConfig.ttl ??= 60;
@@ -174,6 +180,37 @@ export class CachedFediseerApiService {
);
}
+ public getAvailableTags(cacheConfig: CacheConfiguration = {}): Observable {
+ cacheConfig.type ??= CacheType.Permanent;
+ cacheConfig.ttl ??= 300;
+
+ const cacheKey = `api.tags${cacheConfig.ttl}`;
+
+ const item = this.getCacheItem(cacheKey, cacheConfig)!;
+
+ if (item.isHit && !cacheConfig.clear) {
+ return of(item.value!);
+ }
+
+ return this.getWhitelistedInstances()
+ .pipe(
+ map (response => {
+ if (!response.success) {
+ return [];
+ }
+
+ return response.successResponse!.instances.flatMap(instance => instance.tags);
+ }),
+ tap (result => {
+ item.value = result;
+ if (cacheConfig.ttl! >= 0) {
+ item.expiresAt = new Date(new Date().getTime() + (cacheConfig.ttl! * 1_000));
+ }
+ this.saveCacheItem(item, cacheConfig);
+ }),
+ )
+ }
+
public clearCache(): void {
this.runtimeCache.clear();
this.permanentCache.clear();
diff --git a/src/app/services/fediseer-api.service.ts b/src/app/services/fediseer-api.service.ts
index b0dd35f..1fd3fb4 100644
--- a/src/app/services/fediseer-api.service.ts
+++ b/src/app/services/fediseer-api.service.ts
@@ -18,6 +18,7 @@ import {ResetApiKeyResponse} from "../response/reset-api-key.response";
import {PrivateMessageProxy} from "../types/private-message-proxy";
import {SolicitationInstanceDetailResponse} from "../response/solicitation-instance-detail.response";
import {ActionLogFilter} from "../types/action-log.filter";
+import {WhitelistFilter} from "../types/whitelist-filter";
export interface ApiResponse {
success: boolean;
@@ -177,15 +178,21 @@ export class FediseerApiService {
return this.sendRequest(HttpMethod.Patch, `hesitations/${instance}`, body);
}
- public getWhitelistedInstances(): Observable>> {
+ public getWhitelistedInstances(filter: WhitelistFilter = {}): Observable>> {
const maxPerPage = 100; // from api
+ let body: {[key: string]: string} = {};
+ if (filter.tags !== undefined) {
+ body['tags_csv'] = filter.tags.join(',');
+ }
+
const sendRequest = (page: number, limit: number): Observable>> => this.sendRequest(
HttpMethod.Get,
`whitelist`,
{
page: String(page),
limit: String(limit),
+ ...body,
},
);
@@ -380,6 +387,18 @@ export class FediseerApiService {
return this.sendRequest(HttpMethod.Post, `solicitations`, body);
}
+ public tagInstance(tags: string[]): Observable> {
+ return this.sendRequest(HttpMethod.Put, `tags`, {
+ tags_csv: tags.join(','),
+ });
+ }
+
+ public removeInstanceTags(tags: string[]): Observable> {
+ return this.sendRequest(HttpMethod.Delete, `tags`, {
+ tags_csv: tags.join(','),
+ });
+ }
+
private sendRequest(
method: HttpMethod,
endpoint: string,
diff --git a/src/app/solicitations/pages/list-solicitations/list-solicitations.component.ts b/src/app/solicitations/pages/list-solicitations/list-solicitations.component.ts
index 2e9af2a..bd0da43 100644
--- a/src/app/solicitations/pages/list-solicitations/list-solicitations.component.ts
+++ b/src/app/solicitations/pages/list-solicitations/list-solicitations.component.ts
@@ -60,7 +60,7 @@ export class ListSolicitationsComponent implements OnInit {
this.instances = this.instances.filter(item => item.domain !== instance);
}
this.loading = false;
- this.cachedApi.getWhitelistedInstances({clear: true}).subscribe();
+ this.cachedApi.clearWhitelistCache();
this.cachedApi.getGuaranteesByInstance(this.authManager.currentInstanceSnapshot.name, {clear: true}).subscribe();
}
}
diff --git a/src/app/types/whitelist-filter.ts b/src/app/types/whitelist-filter.ts
new file mode 100644
index 0000000..5dbfc0a
--- /dev/null
+++ b/src/app/types/whitelist-filter.ts
@@ -0,0 +1,3 @@
+export interface WhitelistFilter {
+ tags?: string[];
+}