229 lines
12 KiB
Plaintext
229 lines
12 KiB
Plaintext
@using LucideBlazor
|
|
@using Moonlight.Shared.Http.Responses.Admin
|
|
@using ShadcnBlazor.Accordions
|
|
@using ShadcnBlazor.Alerts
|
|
@using ShadcnBlazor.Buttons
|
|
@using ShadcnBlazor.Cards
|
|
@using ShadcnBlazor.Emptys
|
|
@using ShadcnBlazor.Extras.Common
|
|
@using ShadcnBlazor.Spinners
|
|
|
|
@inject HttpClient HttpClient
|
|
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-5 mt-5">
|
|
<div class="col-span-1">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Automatic diagnosis</CardTitle>
|
|
<CardDescription>
|
|
Use a diagnostic report to share configuration details and errors with Moonlight developers, with
|
|
sensitive data automatically censored.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent ClassName="flex flex-col gap-y-5">
|
|
<Alert
|
|
ClassName="w-full flex flex-row items-center gap-3 border-yellow-500/80 bg-yellow-500/5 text-yellow-500">
|
|
<div class="flex shrink-0 items-center">
|
|
<TriangleAlertIcon ClassName="size-6 text-yellow-500/60"/>
|
|
</div>
|
|
<div class="flex flex-1 items-center justify-between gap-4">
|
|
<div class="flex flex-col gap-0.5">
|
|
<AlertTitle>Notice</AlertTitle>
|
|
<AlertDescription ClassName="text-yellow-500/80">
|
|
Only share these reports with the moonlight developers or the corresponding plugin
|
|
developers.
|
|
Even though we do our best to censor sensitive data it may still contain information you
|
|
dont want a random person on the internet to know
|
|
</AlertDescription>
|
|
</div>
|
|
</div>
|
|
</Alert>
|
|
</CardContent>
|
|
<CardFooter ClassName="justify-end">
|
|
<WButtom OnClick="DiagnoseAsync">
|
|
<StethoscopeIcon/>
|
|
Start diagnostics
|
|
</WButtom>
|
|
</CardFooter>
|
|
</Card>
|
|
</div>
|
|
<div class="col-span-1">
|
|
<Card>
|
|
<CardContent ClassName="flex justify-center items-center">
|
|
@if (IsLoading)
|
|
{
|
|
<Spinner ClassName="size-10"/>
|
|
}
|
|
else
|
|
{
|
|
if (HasDiagnosed)
|
|
{
|
|
if (Entries.Length == 0)
|
|
{
|
|
<Empty>
|
|
<EmptyHeader>
|
|
<EmptyMedia Variant="EmptyMediaVariant.Icon">
|
|
<SearchIcon/>
|
|
</EmptyMedia>
|
|
<EmptyTitle>No results available</EmptyTitle>
|
|
<EmptyDescription>
|
|
Diagnosis didnt return any results
|
|
</EmptyDescription>
|
|
</EmptyHeader>
|
|
</Empty>
|
|
}
|
|
else
|
|
{
|
|
<Accordion
|
|
ClassName="w-full"
|
|
Type="AccordionType.Single">
|
|
|
|
@for (var i = 0; i < Entries.Length; i++)
|
|
{
|
|
var entry = Entries[i];
|
|
|
|
var textColor = entry.Level switch
|
|
{
|
|
DiagnoseLevel.Error => "text-destructive",
|
|
DiagnoseLevel.Warning => "text-yellow-300",
|
|
DiagnoseLevel.Healthy => "text-green-500"
|
|
};
|
|
|
|
<AccordionItem
|
|
ClassName="overflow-hidden border bg-background px-4 first:rounded-t-lg last:rounded-b-lg last:border-b"
|
|
Value="@($"diagnoseEntry{i}")">
|
|
|
|
<AccordionTrigger className="hover:no-underline">
|
|
<div class="flex items-center gap-3">
|
|
|
|
@switch (entry.Level)
|
|
{
|
|
case DiagnoseLevel.Error:
|
|
<CircleXIcon ClassName="@textColor"/>
|
|
break;
|
|
|
|
case DiagnoseLevel.Warning:
|
|
<TriangleAlertIcon ClassName="@textColor"/>
|
|
break;
|
|
|
|
case DiagnoseLevel.Healthy:
|
|
<CircleCheckIcon ClassName="@textColor"/>
|
|
break;
|
|
}
|
|
|
|
<div class="flex flex-col items-start text-left">
|
|
<span class="@textColor">
|
|
@entry.Title
|
|
</span>
|
|
<span class="text-sm text-muted-foreground">
|
|
@(string.Join(" / ", entry.Tags))
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent ClassName="ps-7">
|
|
<div class="text-muted-foreground flex flex-col gap-y-3">
|
|
|
|
@if (!string.IsNullOrWhiteSpace(entry.StackStrace))
|
|
{
|
|
<div
|
|
class="rounded-xl p-2.5 bg-black max-h-36 overflow-auto scrollbar-thin">
|
|
@entry.StackStrace
|
|
</div>
|
|
}
|
|
|
|
@if (!string.IsNullOrWhiteSpace(entry.Message))
|
|
{
|
|
<p>
|
|
@entry.Message
|
|
</p>
|
|
}
|
|
|
|
@if (
|
|
!string.IsNullOrWhiteSpace(entry.ReportUrl) ||
|
|
!string.IsNullOrWhiteSpace(entry.StackStrace) ||
|
|
!string.IsNullOrWhiteSpace(entry.SolutionUrl)
|
|
)
|
|
{
|
|
<div class="flex justify-end gap-x-1">
|
|
@if (!string.IsNullOrWhiteSpace(entry.StackStrace))
|
|
{
|
|
<Button Variant="ButtonVariant.Outline">
|
|
<CopyIcon/>
|
|
Copy
|
|
</Button>
|
|
}
|
|
|
|
@if (!string.IsNullOrWhiteSpace(entry.SolutionUrl))
|
|
{
|
|
<Button Variant="ButtonVariant.Outline">
|
|
<Slot>
|
|
<a href="@entry.SolutionUrl" @attributes="context">
|
|
<WrenchIcon/>
|
|
Show suggested solution
|
|
</a>
|
|
</Slot>
|
|
</Button>
|
|
}
|
|
|
|
@if (!string.IsNullOrWhiteSpace(entry.ReportUrl))
|
|
{
|
|
<Button Variant="ButtonVariant.Outline">
|
|
<Slot>
|
|
<a href="@entry.ReportUrl" @attributes="context">
|
|
<GitBranchIcon/>
|
|
Report on Github
|
|
</a>
|
|
</Slot>
|
|
</Button>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
}
|
|
</Accordion>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<Empty>
|
|
<EmptyHeader>
|
|
<EmptyMedia Variant="EmptyMediaVariant.Icon">
|
|
<CircleQuestionMarkIcon/>
|
|
</EmptyMedia>
|
|
<EmptyTitle>No results available yet</EmptyTitle>
|
|
<EmptyDescription>
|
|
Press the start button to start the automatic diagnosis
|
|
</EmptyDescription>
|
|
</EmptyHeader>
|
|
</Empty>
|
|
}
|
|
}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
|
|
@code
|
|
{
|
|
private bool IsLoading = false;
|
|
private bool HasDiagnosed = false;
|
|
private DiagnoseResultResponse[] Entries;
|
|
|
|
private async Task DiagnoseAsync()
|
|
{
|
|
IsLoading = true;
|
|
HasDiagnosed = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
var results = await HttpClient.GetFromJsonAsync<DiagnoseResultResponse[]>("api/admin/system/diagnose");
|
|
Entries = results ?? [];
|
|
|
|
IsLoading = false;
|
|
HasDiagnosed = true;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|