@inherits LocalizableComponentBase
@implements IAsyncDisposable
@* The persona's whole archive (/clientapi/persona/{id}/archive; owner decision 2026-10-07): made on PrivaPub in Mastodon's
layout and downloaded through a link, or another archive (its own, or Mastodon's) uploaded in pieces straight from
the picked file (js/transfer.js) and imported into it, the parts chosen. Imported posts are delivered to no one. *@
@Localizer["This persona's archive"]
@Localizer["Everything the persona posted, with its pictures, what it follows, blocks and mutes, its lists, bookmarks and filters, in the archive Mastodon makes. Nothing of your login or your other personas."]
@if (state.ExportState is "queued" or "running")
{
}
else
{
}
@Localizer["Make the archive"]
@if (state.ExportState == "ready")
{
@if (link is null)
{
@Localizer["Get the link"]
}
else
{
@Localizer["Download {0}", state.ExportBytes.GetFileSize(Localizer)]
}
@Localizer["Made {0}; kept until {1}.", state.ExportReadyAt?.GetPassedTime(Localizer) ?? "", state.ExportExpiresAt?.ToLocalTime().ToString(SUtility.dateTimeFormatExt) ?? ""]
}
@if (state.ExportState == "failed")
{
}
@Localizer["Restore an archive into this persona"]
@Localizer["An archive made here, or by Mastodon. Its posts arrive on this persona's profile without being sent to anyone; follows are asked again."]
@foreach (var part in Parts)
{
}
@Localizer["Liking again tells each post's author; located and scheduled posts come from PrivaPub's archives only."]
@if (!Importing)
{
@Localizer["Import"]
}
else
{
@Localizer["Stop"]
}
@if (uploading)
{
@Localizer["Sending {0} of {1}", uploaded.GetFileSize(Localizer), uploadSize.GetFileSize(Localizer)]
}
@if (state.ImportState is not (null or "none"))
{
@if (state.ImportState is "queued" or "running")
{
}
@(state.ImportState switch
{
"queued" => Localizer["Waiting to start."],
"running" => Localizer["Importing: {0} of {1} read.", state.ImportDone, state.ImportTotal],
"done" => Localizer["Imported."],
"stopped" => Localizer["Stopped."],
_ => Localizer["The import failed: {0}", state.ImportError ?? ""]
})
@if (state.ImportFrom is { Length: > 0 } from)
{
@(state.ImportSameActor ? Localizer["From this persona's own archive."] : Localizer["From {0}.", from])
}
@foreach (var (what, count) in state.ImportCounts.OrderBy(c => c.Key, StringComparer.Ordinal))
{
- @count × @CountName(what)
}
}
@code {
[Inject] ArchiveService Archives { get; set; }
[Inject] TokenAuthStateProvider AuthStateProvider { get; set; }
[Inject] AppConfiguration Configuration { get; set; }
[Inject] IJSRuntime JS { get; set; }
const string FileInput = "input[data-archive-file]";
static readonly TimeSpan PollEvery = TimeSpan.FromSeconds(3);
static readonly string[] Parts = ["posts", "profile", "follows", "blocks", "mutes", "domainblocks", "lists", "bookmarks", "filters", "tags",
"notificationpolicy", "pins", "located", "scheduled", "likes"];
ViewPersonaArchive state = new();
string loadedFor;
HashSet