Merge branch 'develop' of https://github.com/NodeBB/NodeBB into develop

This commit is contained in:
Barış Soner Uşaklı
2026-02-26 14:42:07 -05:00
64 changed files with 804 additions and 351 deletions

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Parametrlər",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Görünüş",
"appearance/themes": "Mövzular",
"appearance/skins": "Örtüklər",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Настройки на %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Външен вид",
"appearance/themes": "Теми",
"appearance/skins": "Облици",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -38,7 +38,7 @@
"settings/tags": "Štítky",
"settings/notifications": "Oznámení",
"settings/api": "API Access",
"settings/activitypub": "Federation (ActivityPub)",
"settings/activitypub": "Federace (AcitivityPub)",
"settings/sounds": "Sounds",
"settings/social": "Social",
"settings/cookies": "Cookies",
@@ -48,6 +48,13 @@
"settings.page-title": "Nastavení %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Vzhled",
"appearance/themes": "Motivy",
"appearance/skins": "Vzhledy",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -38,7 +38,7 @@
"settings/tags": "Tags",
"settings/notifications": "Benachrichtigungen",
"settings/api": "API-Zugriff",
"settings/activitypub": "Federation (ActivityPub)",
"settings/activitypub": "Föderation (ActivityPub)",
"settings/sounds": "Sounds",
"settings/social": "Social",
"settings/cookies": "Cookies",
@@ -48,6 +48,13 @@
"settings.page-title": "%1 Einstellungen",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Aussehen",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Opciones",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Apariencia",
"appearance/themes": "Temas",
"appearance/skins": "Pieles",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "تم‌ها",
"appearance/skins": "پوسته‌ها",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Teemat",

View File

@@ -38,7 +38,7 @@
"settings/tags": "Mots-clés",
"settings/notifications": "Notifications",
"settings/api": "Gestion API",
"settings/activitypub": "Federation (ActivityPub)",
"settings/activitypub": "Fédération (ActivityPub)",
"settings/sounds": "Sons",
"settings/social": "Social",
"settings/cookies": "Cookies",
@@ -48,6 +48,13 @@
"settings.page-title": "Réglages %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Apparence",
"appearance/themes": "Thèmes",
"appearance/skins": "habillages",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 הגדרות",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "מראה חיצוני",
"appearance/themes": "ערכות נושא",
"appearance/skins": "עיצובים",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Postavke",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Izgled",
"appearance/themes": "Predlošci",
"appearance/skins": "Izgled",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Beállítások",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Megjelenés",
"appearance/themes": "Témák",
"appearance/skins": "Téma variációk",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Կարգավորումներ",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Արտաքին տեսք",
"appearance/themes": "Թեմաներ",
"appearance/skins": "Շապիկներ",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Impostazioni",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Stile",
"appearance/themes": "Themi",
"appearance/skins": "Skin",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1の設定",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "外観",
"appearance/themes": "テーマ",
"appearance/skins": "スキン",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 설정",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "외관",
"appearance/themes": "테마",
"appearance/skins": "스킨",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 — iestatījumi",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Izskats",
"appearance/themes": "Tēmas",
"appearance/skins": "Ādiņas",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Innstillinger",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Utseende",
"appearance/themes": "Temaer",
"appearance/skins": "Drakter",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themas",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Innstillingar",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Utseende",
"appearance/themes": "Tema",
"appearance/skins": "Utsjånad",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Ustawienia %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Wygląd",
"appearance/themes": "Style",
"appearance/skins": "Skórki",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Configurações %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Aparência",
"appearance/themes": "Temas",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Definições",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Aparência",
"appearance/themes": "Temas",
"appearance/skins": "Máscaras",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Настройки %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Оформление",
"appearance/themes": "Темы",
"appearance/skins": "Стили",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Nastavenia %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Vzhľad",
"appearance/themes": "Motívy",
"appearance/skins": "Vzhľady",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 nastavitve",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Videz",
"appearance/themes": "Teme",
"appearance/skins": "Preobleke",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Podešavanja",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Izgled",
"appearance/themes": "Teme",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Settings",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Appearance",
"appearance/themes": "Themes",
"appearance/skins": "Skins",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 Ayar",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Görünüm",
"appearance/themes": "Temalar",
"appearance/skins": "Deriler",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Налаштування %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Зовнішній вигляд",
"appearance/themes": "Теми",
"appearance/skins": "Стилі",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 کی ترتیبات",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "ظاہری شکل",
"appearance/themes": "تھیمز",
"appearance/skins": "جلدیں",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "Cài đặt %1",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "Trực quan",
"appearance/themes": "Giao diện",
"appearance/skins": "Trang điểm",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 设置",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "界面",
"appearance/themes": "主题",
"appearance/skins": "皮肤",

View File

@@ -48,6 +48,13 @@
"settings.page-title": "%1 設置",
"section-federation": "Federation",
"federation/general": "General",
"federation/rules": "Categorization",
"federation/relays": "Relays",
"federation/pruning": "Content Pruning",
"federation/safety": "Trust & Safety",
"section-appearance": "外觀",
"appearance/themes": "佈景主題",
"appearance/skins": "配色",

View File

@@ -0,0 +1,70 @@
'use strict';
import { post, del } from 'api';
import { error } from 'alerts';
import { render } from 'benchpress';
export function init() {
setupRelays();
};
function setupRelays() {
const relaysEl = document.getElementById('relays');
if (relaysEl) {
relaysEl.addEventListener('click', (e) => {
const subselector = e.target.closest('[data-action]');
if (subselector) {
const action = subselector.getAttribute('data-action');
switch (action) {
case 'relays.add': {
throwModal();
break;
}
case 'relays.remove': {
const url = subselector.closest('tr').getAttribute('data-url');
del(`/admin/activitypub/relays/${encodeURIComponent(url)}`, {}).then(async (data) => {
const html = await app.parseAndTranslate('admin/settings/activitypub', 'relays', { relays: data });
const tbodyEl = document.querySelector('#relays tbody');
if (tbodyEl) {
$(tbodyEl).html(html);
}
}).catch(error);
}
}
}
});
}
}
function throwModal() {
render('admin/partials/activitypub/relays', {}).then(function (html) {
const submit = function () {
const formEl = modal.find('form').get(0);
const payload = Object.fromEntries(new FormData(formEl));
post('/admin/activitypub/relays', payload).then(async (data) => {
const html = await app.parseAndTranslate('admin/settings/activitypub', 'relays', { relays: data });
const tbodyEl = document.querySelector('#relays tbody');
if (tbodyEl) {
$(tbodyEl).html(html);
}
}).catch(error);
};
const modal = bootbox.dialog({
title: '[[admin/settings/activitypub:relays.add]]',
message: html,
buttons: {
save: {
label: '[[global:save]]',
className: 'btn-primary',
callback: submit,
},
},
});
modal.on('shown.bs.modal', function () {
modal.find('input').focus();
});
});
}

View File

@@ -0,0 +1,122 @@
'use strict';
import { post, del, put } from 'api';
import { error } from 'alerts';
import { render } from 'benchpress';
import { translate } from 'translator';
import * as categorySelector from 'categorySelector';
export function init() {
setupRules();
};
function setupRules() {
const rulesEl = document.getElementById('rules');
if (!rulesEl) {
return;
}
rulesEl.addEventListener('click', (e) => {
const subselector = e.target.closest('[data-action]');
if (subselector) {
const action = subselector.getAttribute('data-action');
switch (action) {
case 'rules.add': {
throwModal();
break;
}
case 'rules.delete': {
const rid = subselector.closest('tr').getAttribute('data-rid');
del(`/admin/activitypub/rules/${rid}`, {}).then(async (data) => {
const html = await render('admin/settings/activitypub', { rules: data }, 'rules');
const tbodyEl = document.querySelector('#rules tbody');
if (tbodyEl) {
tbodyEl.innerHTML = html;
}
}).catch(error);
}
}
}
});
const tbodyEl = $(rulesEl).find('tbody');
tbodyEl.sortable({
handle: '.drag-handle',
helper: fixWidthHelper,
placeholder: 'ui-state-highlight',
axis: 'y',
update: function () {
const rids = [];
tbodyEl.find('tr').each(function () {
rids.push($(this).data('rid'));
});
put('/admin/activitypub/rules/order', { rids }).catch(error);
},
});
function fixWidthHelper(e, ui) {
ui.children().each(function () {
$(this).width($(this).width());
});
return ui;
}
}
function throwModal() {
render('admin/partials/activitypub/rules', {}).then(function (html) {
const submit = function () {
const formEl = modal.find('form').get(0);
const payload = Object.fromEntries(new FormData(formEl));
post('/admin/activitypub/rules', payload).then(async (data) => {
const html = await render('admin/settings/activitypub', { rules: data }, 'rules');
const tbodyEl = document.querySelector('#rules tbody');
if (tbodyEl) {
tbodyEl.innerHTML = html;
}
}).catch(error);
};
const modal = bootbox.dialog({
title: '[[admin/settings/activitypub:rules.add]]',
message: html,
buttons: {
save: {
label: '[[global:save]]',
className: 'btn-primary',
callback: submit,
},
},
});
modal.on('shown.bs.modal', function () {
modal.find('input').focus();
});
// help text
const updateHelp = async (key, el) => {
const text = await translate(`[[admin/settings/activitypub:rules.help-${key}]]`);
el.innerHTML = text;
};
const helpTextEl = modal.get(0).querySelector('#help-text');
const typeEl = modal.get(0).querySelector('#type');
updateHelp(modal.get(0).querySelector('#type option').value, helpTextEl);
if (typeEl && helpTextEl) {
typeEl.addEventListener('change', function () {
updateHelp(this.value, helpTextEl);
});
}
// category switcher
categorySelector.init(modal.find('[component="category-selector"]'), {
onSelect: function (selectedCategory) {
modal.find('[name="cid"]').val(selectedCategory.cid);
},
cacheList: false,
showLinks: true,
template: 'admin/partials/category/selector-dropdown-right',
});
});
}

View File

@@ -1,193 +0,0 @@
'use strict';
define('admin/settings/activitypub', [
'benchpress',
'bootbox',
'categorySelector',
'api',
'alerts',
'translator',
'jquery-ui/widgets/sortable',
], function (Benchpress, bootbox, categorySelector, api, alerts, translator) {
const ActivityPub = {};
ActivityPub.init = function () {
setupRules();
setupRelays();
};
ActivityPub.throwRulesModal = function () {
Benchpress.render('admin/partials/activitypub/rules', {}).then(function (html) {
const submit = function () {
const formEl = modal.find('form').get(0);
const payload = Object.fromEntries(new FormData(formEl));
api.post('/admin/activitypub/rules', payload).then(async (data) => {
const html = await Benchpress.render('admin/settings/activitypub', { rules: data }, 'rules');
const tbodyEl = document.querySelector('#rules tbody');
if (tbodyEl) {
tbodyEl.innerHTML = html;
}
}).catch(alerts.error);
};
const modal = bootbox.dialog({
title: '[[admin/settings/activitypub:rules.add]]',
message: html,
buttons: {
save: {
label: '[[global:save]]',
className: 'btn-primary',
callback: submit,
},
},
});
modal.on('shown.bs.modal', function () {
modal.find('input').focus();
});
// help text
const updateHelp = async (key, el) => {
const text = await translator.translate(`[[admin/settings/activitypub:rules.help-${key}]]`);
el.innerHTML = text;
};
const helpTextEl = modal.get(0).querySelector('#help-text');
const typeEl = modal.get(0).querySelector('#type');
updateHelp(modal.get(0).querySelector('#type option').value, helpTextEl);
if (typeEl && helpTextEl) {
typeEl.addEventListener('change', function () {
updateHelp(this.value, helpTextEl);
});
}
// category switcher
categorySelector.init(modal.find('[component="category-selector"]'), {
onSelect: function (selectedCategory) {
modal.find('[name="cid"]').val(selectedCategory.cid);
},
cacheList: false,
showLinks: true,
template: 'admin/partials/category/selector-dropdown-right',
});
});
};
ActivityPub.throwRelaysModal = function () {
Benchpress.render('admin/partials/activitypub/relays', {}).then(function (html) {
const submit = function () {
const formEl = modal.find('form').get(0);
const payload = Object.fromEntries(new FormData(formEl));
api.post('/admin/activitypub/relays', payload).then(async (data) => {
const html = await app.parseAndTranslate('admin/settings/activitypub', 'relays', { relays: data });
const tbodyEl = document.querySelector('#relays tbody');
if (tbodyEl) {
$(tbodyEl).html(html);
}
}).catch(alerts.error);
};
const modal = bootbox.dialog({
title: '[[admin/settings/activitypub:relays.add]]',
message: html,
buttons: {
save: {
label: '[[global:save]]',
className: 'btn-primary',
callback: submit,
},
},
});
modal.on('shown.bs.modal', function () {
modal.find('input').focus();
});
});
};
function setupRules() {
const rulesEl = document.getElementById('rules');
if (!rulesEl) {
return;
}
rulesEl.addEventListener('click', (e) => {
const subselector = e.target.closest('[data-action]');
if (subselector) {
const action = subselector.getAttribute('data-action');
switch (action) {
case 'rules.add': {
ActivityPub.throwRulesModal();
break;
}
case 'rules.delete': {
const rid = subselector.closest('tr').getAttribute('data-rid');
api.del(`/admin/activitypub/rules/${rid}`, {}).then(async (data) => {
const html = await Benchpress.render('admin/settings/activitypub', { rules: data }, 'rules');
const tbodyEl = document.querySelector('#rules tbody');
if (tbodyEl) {
tbodyEl.innerHTML = html;
}
}).catch(alerts.error);
}
}
}
});
const tbodyEl = $(rulesEl).find('tbody');
tbodyEl.sortable({
handle: '.drag-handle',
helper: fixWidthHelper,
placeholder: 'ui-state-highlight',
axis: 'y',
update: function () {
const rids = [];
tbodyEl.find('tr').each(function () {
rids.push($(this).data('rid'));
});
api.put('/admin/activitypub/rules/order', { rids }).catch(alerts.error);
},
});
function fixWidthHelper(e, ui) {
ui.children().each(function () {
$(this).width($(this).width());
});
return ui;
}
}
function setupRelays() {
const relaysEl = document.getElementById('relays');
if (relaysEl) {
relaysEl.addEventListener('click', (e) => {
const subselector = e.target.closest('[data-action]');
if (subselector) {
const action = subselector.getAttribute('data-action');
switch (action) {
case 'relays.add': {
ActivityPub.throwRelaysModal();
break;
}
case 'relays.remove': {
const url = subselector.closest('tr').getAttribute('data-url');
api.del(`/admin/activitypub/relays/${encodeURIComponent(url)}`, {}).then(async (data) => {
const html = await app.parseAndTranslate('admin/settings/activitypub', 'relays', { relays: data });
const tbodyEl = document.querySelector('#relays tbody');
if (tbodyEl) {
$(tbodyEl).html(html);
}
}).catch(alerts.error);
}
}
}
});
}
}
return ActivityPub;
});

View File

@@ -14,6 +14,7 @@ const adminController = {
groups: require('./admin/groups'),
digest: require('./admin/digest'),
appearance: require('./admin/appearance'),
federation: require('./admin/federation'),
extend: {
widgets: require('./admin/widgets'),
rewards: require('./admin/rewards'),

View File

@@ -0,0 +1,43 @@
'use strict';
const activitypub = require('../../activitypub');
const federationController = module.exports;
federationController.general = function (req, res) {
res.render(`admin/federation/general`, {
title: '[[admin/menu:federation/general]]',
});
};
federationController.rules = async function (req, res) {
const rules = await activitypub.rules.list();
res.render(`admin/federation/rules`, {
title: '[[admin/menu:federation/rules]]',
rules,
hideSave: true,
});
};
federationController.relays = async function (req, res) {
const relays = await activitypub.relays.list();
res.render(`admin/federation/relays`, {
title: '[[admin/menu:federation/relays]]',
relays,
hideSave: true,
});
};
federationController.pruning = function (req, res) {
res.render(`admin/federation/pruning`, {
title: '[[admin/menu:federation/pruning]]',
});
};
federationController.safety = function (req, res) {
res.render(`admin/federation/safety`, {
title: '[[admin/menu:federation/safety]]',
});
};

View File

@@ -52,6 +52,12 @@ module.exports = function (app, name, middleware, controllers) {
helpers.setupAdminPageRoute(app, `/${name}/settings/web-crawler`, middlewares, controllers.admin.settings.webCrawler);
helpers.setupAdminPageRoute(app, `/${name}/settings/advanced`, middlewares, controllers.admin.settings.advanced);
helpers.setupAdminPageRoute(app, `/${name}/federation/general`, middlewares, controllers.admin.federation.general);
helpers.setupAdminPageRoute(app, `/${name}/federation/rules`, middlewares, controllers.admin.federation.rules);
helpers.setupAdminPageRoute(app, `/${name}/federation/relays`, middlewares, controllers.admin.federation.relays);
helpers.setupAdminPageRoute(app, `/${name}/federation/pruning`, middlewares, controllers.admin.federation.pruning);
helpers.setupAdminPageRoute(app, `/${name}/federation/safety`, middlewares, controllers.admin.federation.safety);
helpers.setupAdminPageRoute(app, `/${name}/appearance/themes`, middlewares, controllers.admin.appearance.themes);
helpers.setupAdminPageRoute(app, `/${name}/appearance/skins`, middlewares, controllers.admin.appearance.skins);
helpers.setupAdminPageRoute(app, `/${name}/appearance/customise`, middlewares, controllers.admin.appearance.customise);

View File

@@ -0,0 +1,49 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<p class="lead">[[admin/settings/activitypub:intro-lead]]</p>
<p>[[admin/settings/activitypub:intro-body]]</p>
<hr />
<div id="general" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:general]]</h5>
<form>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubEnabled">
<label class="form-check-label">[[admin/settings/activitypub:enabled]]</label>
<p class="form-text">[[admin/settings/activitypub:enabled-help]]</p>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubAllowLoopback">
<label class="form-check-label">[[admin/settings/activitypub:allowLoopback]]</label>
<p class="form-text">[[admin/settings/activitypub:allowLoopback-help]]</p>
</div>
</form>
</div>
<div id="probe" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:probe]]</h5>
<form>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubProbe">
<label class="form-check-label">[[admin/settings/activitypub:probe-enabled]]</label>
<p class="form-text">[[admin/settings/activitypub:probe-enabled-help]]</p>
</div>
<div class="mb-3">
<label class="form-label" for="activitypubProbeTimeout">[[admin/settings/activitypub:probe-timeout]]</label>
<input type="number" id="activitypubProbeTimeout" name="activitypubProbeTimeout" data-field="activitypubProbeTimeout" title="[[admin/settings/activitypub:probe-timeout]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:probe-timeout-help]]
</div>
</div>
</form>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>

View File

@@ -0,0 +1,28 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<div id="pruning" class="mb-4">
<form>
<div class="mb-3">
<label class="form-label" for="activitypubContentPruneDays">[[admin/settings/activitypub:content-pruning]]</label>
<input type="number" id="activitypubContentPruneDays" name="activitypubContentPruneDays" data-field="activitypubContentPruneDays" title="[[admin/settings/activitypub:content-pruning]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:content-pruning-help]]
</div>
</div>
<div class="mb-3">
<label class="form-label" for="activitypubUserPruneDays">[[admin/settings/activitypub:user-pruning]]</label>
<input type="number" id="activitypubUserPruneDays" name="activitypubUserPruneDays" data-field="activitypubUserPruneDays" title="[[admin/settings/activitypub:user-pruning]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:user-pruning-help]]
</div>
</div>
</form>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>

View File

@@ -0,0 +1,39 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<div id="relays" class="mb-4">
<p class="lead">[[admin/settings/activitypub:relays.intro]]</p>
<p class="text-warning">[[admin/settings/activitypub:relays.warning]]</p>
<div class="mb-3">
<table class="table table-striped" id="relays">
<thead>
<th>[[admin/settings/activitypub:relays.relay]]</th>
<th>[[admin/settings/activitypub:relays.state]]</th>
<th></th>
</thead>
<tbody>
{{{ each relays }}}
<tr data-url="{./url}">
<td>{./url}</td>
<td>{./label}</td>
<td><a href="#" data-action="relays.remove"><i class="fa fa-trash link-danger"></i></a></td>
</tr>
{{{ end }}}
</tbody>
<tfoot>
<tr>
<td colspan="3">
<button class="btn btn-sm btn-primary" data-action="relays.add">[[admin/settings/activitypub:relays.add]]</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>

View File

@@ -0,0 +1,45 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<div id="rules" class="mb-4">
<p class="lead">[[admin/settings/activitypub:rules-intro]]</p>
<div class="mb-3">
<table class="table table-striped" id="rules">
<thead>
<th></th>
<th>[[admin/settings/activitypub:rules.type]]</th>
<th>[[admin/settings/activitypub:rules.value]]</th>
<th>[[admin/settings/activitypub:rules.cid]]</th>
<th></th>
</thead>
<tbody>
{{{ each rules }}}
<tr data-rid="{./rid}">
<td class="align-items-center" style="cursor: move;">
<i class="fa fa-grip-lines text-muted drag-handle"></i>
</td>
<td>{./type}</td>
<td>{./value}</td>
<td>{./cid}</td>
<td><a href="#" data-action="rules.delete"><i class="fa fa-trash link-danger"></i></a></td>
</tr>
{{{ end }}}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<button class="btn btn-sm btn-primary" data-action="rules.add">[[admin/settings/activitypub:rules.add]]</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>

View File

@@ -0,0 +1,26 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<div id="server-filtering" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:server-filtering]]</h5>
<form>
<div class="mb-3">
<p>[[admin/settings/activitypub:server.filter-help]]</p>
<p>[[admin/settings/activitypub:server.filter-help-hostname]]</p>
<p>[[admin/settings/activitypub:count, {instanceCount}]]</p>
<label for="activitypubFilterList" class="form-label">Filtering list</label>
<textarea class="form-control" id="activitypubFilterList" data-field="activitypubFilterList" rows="10"></textarea>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" id="activitypubFilter" data-field="activitypubFilter" />
<label class="form-check-label" for="activitypubFilter">[[admin/settings/activitypub:server.filter-allow-list]]</label>
</div>
</form>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>

View File

@@ -63,8 +63,8 @@
</div>
{{{ end }}}
<!-- settings menu -->
{{{ if user.privileges.admin:settings }}}
<!-- settings menu -->
<div class="d-flex flex-column">
<button class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSettings" aria-expanded="true" aria-controls="collapseSettings">
<i class="fa fa-fw fa-sliders"></i>
@@ -86,7 +86,6 @@
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/pagination">[[admin/menu:settings/pagination]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/notifications">[[admin/menu:settings/notifications]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/api">[[admin/menu:settings/api]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/activitypub">[[admin/menu:settings/activitypub]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/cookies">[[admin/menu:settings/cookies]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/web-crawler">[[admin/menu:settings/web-crawler]]</a>
<a class="btn btn-ghost btn-sm text-start" href="{relative_path}/admin/settings/advanced">[[admin/menu:settings/advanced]]</a>
@@ -95,6 +94,25 @@
</div>
<!-- federation menu -->
<div class="d-flex flex-column">
<button class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFederation" aria-expanded="true" aria-controls="collapseFederation">
<i class="fa fa-fw fa-circle-nodes"></i>
<div class="flex-1 font-serif text-sm fw-semibold text-start">[[admin/menu:section-federation]]</div>
</button>
<div id="collapseFederation" class="accordion-collapse collapse" data-bs-parent="#accordionACP">
<div class="accordion-body p-0 d-grid">
<a class="btn btn-ghost btn-sm text-start" id="federation-general" href="{relative_path}/admin/federation/general">[[admin/menu:federation/general]]</a>
<a class="btn btn-ghost btn-sm text-start" id="federation-rules" href="{relative_path}/admin/federation/rules">[[admin/menu:federation/rules]]</a>
<a class="btn btn-ghost btn-sm text-start" id="federation-relays" href="{relative_path}/admin/federation/relays">[[admin/menu:federation/relays]]</a>
<a class="btn btn-ghost btn-sm text-start" id="federation-pruning" href="{relative_path}/admin/federation/pruning">[[admin/menu:federation/pruning]]</a>
<a class="btn btn-ghost btn-sm text-start" id="federation-safety" href="{relative_path}/admin/federation/safety">[[admin/menu:federation/safety]]</a>
</div>
</div>
</div>
<!-- appearance menu -->
<div class="d-flex flex-column">
<button class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAppearance" aria-expanded="true" aria-controls="collapseAppearance">

View File

@@ -2,7 +2,9 @@
<div class="col-12 col-md-8 px-0 mb-1 mb-md-0">
<h4 class="fw-bold tracking-tight mb-0">{title}</h4>
</div>
{{{ if !hideSave }}}
<div class="col-12 col-md-4 px-0 px-md-3">
<button id="save" class="btn btn-primary btn-sm fw-semibold ff-secondary w-100 text-center text-nowrap">[[admin/admin:save-changes]]</button>
</div>
{{{ end }}}
</div>

View File

@@ -1,153 +0,0 @@
<div class="acp-page-container">
<!-- IMPORT admin/partials/settings/header.tpl -->
<div class="row settings m-0">
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
<p class="lead">[[admin/settings/activitypub:intro-lead]]</p>
<p>[[admin/settings/activitypub:intro-body]]</p>
<hr />
<div id="general" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:general]]</h5>
<form>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubEnabled">
<label class="form-check-label">[[admin/settings/activitypub:enabled]]</label>
<p class="form-text">[[admin/settings/activitypub:enabled-help]]</p>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubAllowLoopback">
<label class="form-check-label">[[admin/settings/activitypub:allowLoopback]]</label>
<p class="form-text">[[admin/settings/activitypub:allowLoopback-help]]</p>
</div>
</form>
</div>
<div id="probe" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:probe]]</h5>
<form>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubProbe">
<label class="form-check-label">[[admin/settings/activitypub:probe-enabled]]</label>
<p class="form-text">[[admin/settings/activitypub:probe-enabled-help]]</p>
</div>
<div class="mb-3">
<label class="form-label" for="activitypubProbeTimeout">[[admin/settings/activitypub:probe-timeout]]</label>
<input type="number" id="activitypubProbeTimeout" name="activitypubProbeTimeout" data-field="activitypubProbeTimeout" title="[[admin/settings/activitypub:probe-timeout]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:probe-timeout-help]]
</div>
</div>
</form>
</div>
<div id="rules" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:rules]]</h5>
<div class="mb-3">
<p>[[admin/settings/activitypub:rules-intro]]</p>
<table class="table table-striped" id="rules">
<thead>
<th></th>
<th>[[admin/settings/activitypub:rules.type]]</th>
<th>[[admin/settings/activitypub:rules.value]]</th>
<th>[[admin/settings/activitypub:rules.cid]]</th>
<th></th>
</thead>
<tbody>
{{{ each rules }}}
<tr data-rid="{./rid}">
<td class="align-items-center" style="cursor: move;">
<i class="fa fa-grip-lines text-muted drag-handle"></i>
</td>
<td>{./type}</td>
<td>{./value}</td>
<td>{./cid}</td>
<td><a href="#" data-action="rules.delete"><i class="fa fa-trash link-danger"></i></a></td>
</tr>
{{{ end }}}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<button class="btn btn-sm btn-primary" data-action="rules.add">[[admin/settings/activitypub:rules.add]]</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div id="relays" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:relays]]</h5>
<p>[[admin/settings/activitypub:relays.intro]]</p>
<p class="text-warning">[[admin/settings/activitypub:relays.warning]]</p>
<div class="mb-3">
<table class="table table-striped" id="relays">
<thead>
<th>[[admin/settings/activitypub:relays.relay]]</th>
<th>[[admin/settings/activitypub:relays.state]]</th>
<th></th>
</thead>
<tbody>
{{{ each relays }}}
<tr data-url="{./url}">
<td>{./url}</td>
<td>{./label}</td>
<td><a href="#" data-action="relays.remove"><i class="fa fa-trash link-danger"></i></a></td>
</tr>
{{{ end }}}
</tbody>
<tfoot>
<tr>
<td colspan="3">
<button class="btn btn-sm btn-primary" data-action="relays.add">[[admin/settings/activitypub:relays.add]]</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div id="pruning" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:pruning]]</h5>
<form>
<div class="mb-3">
<label class="form-label" for="activitypubContentPruneDays">[[admin/settings/activitypub:content-pruning]]</label>
<input type="number" id="activitypubContentPruneDays" name="activitypubContentPruneDays" data-field="activitypubContentPruneDays" title="[[admin/settings/activitypub:content-pruning]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:content-pruning-help]]
</div>
</div>
<div class="mb-3">
<label class="form-label" for="activitypubUserPruneDays">[[admin/settings/activitypub:user-pruning]]</label>
<input type="number" id="activitypubUserPruneDays" name="activitypubUserPruneDays" data-field="activitypubUserPruneDays" title="[[admin/settings/activitypub:user-pruning]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:user-pruning-help]]
</div>
</div>
</form>
</div>
<div id="server-filtering" class="mb-4">
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:server-filtering]]</h5>
<form>
<div class="mb-3">
<p>[[admin/settings/activitypub:server.filter-help]]</p>
<p>[[admin/settings/activitypub:server.filter-help-hostname]]</p>
<p>[[admin/settings/activitypub:count, {instanceCount}]]</p>
<label for="activitypubFilterList" class="form-label">Filtering list</label>
<textarea class="form-control" id="activitypubFilterList" data-field="activitypubFilterList" rows="10"></textarea>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" id="activitypubFilter" data-field="activitypubFilter" />
<label class="form-check-label" for="activitypubFilter">[[admin/settings/activitypub:server.filter-allow-list]]</label>
</div>
</form>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->
</div>
</div>