122 lines
4.2 KiB
Plaintext
122 lines
4.2 KiB
Plaintext
@inherits LocalizableComponentBase
|
|||
|
|
|
||
|
|
@* Servers blocked for everyone here (/clientapi/admin/domainblocks): suspended (nothing from or to them) or silenced
|
||
|
|
(kept out of the public feeds), their media refused or not, with a comment for the public and one for the admins. *@
|
||
|
|
<div class="flex flex-col gap-3 w-full" data-server-blocks>
|
||
|
|
<EditForm Model="form" OnValidSubmit="Block" class="flex flex-col gap-2 p-3 rounded-xl neo-inset neo-2xs">
|
||
|
|
<DataAnnotationsValidator />
|
||
|
|
<div class="flex flex-wrap gap-2 items-center">
|
||
|
|
<DInput TValue="string" class="flex-1 min-w-48" @bind-Value="form.Domain" Immediate="true" autocomplete="off" maxlength="253"
|
||
|
|
placeholder="@Localizer["A server, e.g. example.social"]" data-server-block-domain>
|
||
|
|
<Prefix><i class="ion-md-globe"></i></Prefix>
|
||
|
|
</DInput>
|
||
|
|
<DToggle LabelText="@Localizer["Suspend (otherwise silence)"]" @bind-Value="form.Suspend" />
|
||
|
|
<DToggle LabelText="@Localizer["Refuse its media"]" @bind-Value="form.RejectMedia" />
|
||
|
|
</div>
|
||
|
|
<DInput TValue="string" @bind-Value="form.PublicComment" Immediate="true" autocomplete="off" maxlength="1000"
|
||
|
|
placeholder="@Localizer["Why, for everyone to read"]" />
|
||
|
|
<DInput TValue="string" @bind-Value="form.PrivateComment" Immediate="true" autocomplete="off" maxlength="1000"
|
||
|
|
placeholder="@Localizer["Why, for the admins only"]" />
|
||
|
|
<ErrorViewer />
|
||
|
|
<DButton Type="submit" Size="DSize.Sm" Color="DColor.Error" class="self-end"
|
||
|
|
Disabled="@(IsDefaultDisabled || isSaving || string.IsNullOrWhiteSpace(form.Domain))">
|
||
|
|
@Localizer["Block server"]
|
||
|
|
</DButton>
|
||
|
|
</EditForm>
|
||
|
|
|
||
|
|
@if (IsLoading)
|
||
|
|
{
|
||
|
|
<p class="flex w-full items-center justify-center gap-2">
|
||
|
|
<DLoading Variant="DLoadingVariant.Dots" LabelText="@Localizer["loading"]" />
|
||
|
|
@Localizer["loading"]
|
||
|
|
</p>
|
||
|
|
}
|
||
|
|
else if (blocks.Count == 0)
|
||
|
|
{
|
||
|
|
<p class="text-sm opacity-70">@Localizer["No server is blocked."]</p>
|
||
|
|
}
|
||
|
|
|
||
|
|
@foreach (var block in blocks)
|
||
|
|
{
|
||
|
|
<div class="flex flex-col gap-1 p-2 rounded-lg neo-raised neo-2xs" data-server-block="@block.Domain">
|
||
|
|
<div class="flex flex-wrap items-center gap-2">
|
||
|
|
<b class="flex-1 min-w-0 truncate">@block.Domain</b>
|
||
|
|
<DBadge Size="DSize.Sm" Variant="DBadgeVariant.Soft" Color="@(block.Severity == "Suspend" ? DColor.Error : DColor.Warning)">
|
||
|
|
@(block.Severity == "Suspend" ? Localizer["Suspended"] : Localizer["Silenced"])
|
||
|
|
</DBadge>
|
||
|
|
@if (block.RejectMedia)
|
||
|
|
{
|
||
|
|
<DBadge Size="DSize.Sm" Variant="DBadgeVariant.Soft">@Localizer["Media refused"]</DBadge>
|
||
|
|
}
|
||
|
|
<span class="text-xs opacity-70" title="@block.CreatedAt.ToLocalTime().ToString(SUtility.dateTimeFormat)">@block.CreatedAt.GetPassedTime(Localizer)</span>
|
||
|
|
<DButton Size="DSize.Sm" Disabled="@(IsDefaultDisabled || busy.Contains(block.Domain))" OnClick="() => Unblock(block)">
|
||
|
|
@Localizer["Unblock"]
|
||
|
|
</DButton>
|
||
|
|
</div>
|
||
|
|
@if (block.PublicComment is { Length: > 0 } publicComment)
|
||
|
|
{
|
||
|
|
<p class="text-xs">@publicComment</p>
|
||
|
|
}
|
||
|
|
@if (block.PrivateComment is { Length: > 0 } privateComment)
|
||
|
|
{
|
||
|
|
<p class="text-xs opacity-70"><i class="ion-md-lock"></i> @privateComment</p>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
@code {
|
||
|
|
[Inject] AdminService AdminService { get; set; }
|
||
|
|
|
||
|
|
List<ViewDomainBlock> blocks = [];
|
||
|
|
DomainBlockForm form = new();
|
||
|
|
bool isSaving;
|
||
|
|
HashSet<string> busy = [];
|
||
|
|
|
||
|
|
protected override async Task OnInitializedAsync()
|
||
|
|
{
|
||
|
|
if (CascadingState.IsOffline)
|
||
|
|
{
|
||
|
|
WhenOnline(LoadData);
|
||
|
|
StartOnlinePolling();
|
||
|
|
IsLoading = false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
await LoadData();
|
||
|
|
IsLoading = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
async Task LoadData() => blocks = await AdminService.ServerBlocks();
|
||
|
|
|
||
|
|
async Task Block()
|
||
|
|
{
|
||
|
|
isSaving = true;
|
||
|
|
var result = await AdminService.BlockServer(form);
|
||
|
|
isSaving = false;
|
||
|
|
if (result.IsInvalid)
|
||
|
|
{
|
||
|
|
Toast.AddResponseError(result);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var block = (ViewDomainBlock)result.Data;
|
||
|
|
blocks = [.. blocks.Where(b => b.Domain != block.Domain).Append(block).OrderBy(b => b.Domain, StringComparer.Ordinal)];
|
||
|
|
form = new();
|
||
|
|
Toast.AddResponseSuccess(Localizer["{0} is blocked.", block.Domain]);
|
||
|
|
}
|
||
|
|
|
||
|
|
async Task Unblock(ViewDomainBlock block)
|
||
|
|
{
|
||
|
|
busy.Add(block.Domain);
|
||
|
|
var result = await AdminService.UnblockServer(block.Domain);
|
||
|
|
busy.Remove(block.Domain);
|
||
|
|
if (result.IsInvalid)
|
||
|
|
{
|
||
|
|
Toast.AddResponseError(result);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
blocks.Remove(block);
|
||
|
|
}
|
||
|
|
}
|