mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-09-27 02:13:36 +00:00
259 lines
13 KiB
Plaintext
259 lines
13 KiB
Plaintext
|
|
@using AIStudio.Tools.ChatArchive
|
||
|
|
@inherits SettingsPanelBase
|
||
|
|
|
||
|
|
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.SettingsBackupRestore" HeaderText="@T("Data Backup & Restore")" ExpandedChanged="@this.PanelExpandedChanged">
|
||
|
|
<MudText Typo="Typo.body1" Class="mb-3">
|
||
|
|
@T("Save your chats as an archive file, for example as a backup or to move them to another computer. You can read such archives back into AI Studio at any time.")
|
||
|
|
</MudText>
|
||
|
|
|
||
|
|
<MudTabs Elevation="0" Rounded="@true" ApplyEffectsToContainer="@true" Outlined="@true" PanelClass="pa-4" ActivePanelIndexChanged="@this.ActivePanelChanged">
|
||
|
|
<MudTabPanel Text="@T("Export")" Icon="@Icons.Material.Filled.Archive" Disabled="@this.isBusy">
|
||
|
|
|
||
|
|
@if (this.isLoadingWorkspaces)
|
||
|
|
{
|
||
|
|
<MudProgressLinear Indeterminate="@true" Color="Color.Primary" Class="mb-3"/>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
@if (!string.IsNullOrWhiteSpace(this.workspaceLoadError))
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Error" Dense="@true" Class="mb-3">
|
||
|
|
@this.workspaceLoadError
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else if (!this.HasWorkspacesToExport)
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Info" Dense="@true" Class="mb-3">
|
||
|
|
@T("There are no chats to export yet.")
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2" Class="mb-2">
|
||
|
|
@T("Choose the workspaces you want to export.")
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
|
||
|
|
@* The refresh button stays available even when nothing could be read,
|
||
|
|
so that a failed attempt can be repeated: *@
|
||
|
|
<MudStack Row="@true" Spacing="2" Class="mb-2">
|
||
|
|
@if (this.HasWorkspacesToExport)
|
||
|
|
{
|
||
|
|
<MudButton Variant="Variant.Text" Color="Color.Default" StartIcon="@Icons.Material.Filled.SelectAll" OnClick="@(() => this.SelectAllWorkspaces(true))" Disabled="@this.isBusy">
|
||
|
|
@T("Select all")
|
||
|
|
</MudButton>
|
||
|
|
<MudButton Variant="Variant.Text" Color="Color.Default" StartIcon="@Icons.Material.Filled.Deselect" OnClick="@(() => this.SelectAllWorkspaces(false))" Disabled="@this.isBusy">
|
||
|
|
@T("Select none")
|
||
|
|
</MudButton>
|
||
|
|
}
|
||
|
|
<MudButton Variant="Variant.Text" Color="Color.Default" StartIcon="@Icons.Material.Filled.Refresh" OnClick="@(async () => await this.LoadWorkspacesAsync())" Disabled="@this.isBusy">
|
||
|
|
@T("Refresh")
|
||
|
|
</MudButton>
|
||
|
|
</MudStack>
|
||
|
|
|
||
|
|
@if (this.HasWorkspacesToExport)
|
||
|
|
{
|
||
|
|
<MudPaper Outlined="@true" Class="pa-3 mb-3">
|
||
|
|
@foreach (var selection in this.workspaceSelections)
|
||
|
|
{
|
||
|
|
<div>
|
||
|
|
<MudCheckBox T="bool" Value="@selection.IsSelected" ValueChanged="@(value => this.WorkspaceSelectionChanged(selection, value))" Color="Color.Primary" Dense="@true" Disabled="@this.isBusy" Label="@($"{selection.Name} ({string.Format(T("{0} chats"), selection.ChatCount)})")"/>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
|
||
|
|
@if (this.temporaryChatCount > 0)
|
||
|
|
{
|
||
|
|
<div>
|
||
|
|
<MudCheckBox T="bool" @bind-Value="@this.includeTemporaryChats" Color="Color.Primary" Dense="@true" Disabled="@this.isBusy" Label="@($"{T("Temporary chats")} ({string.Format(T("{0} chats"), this.temporaryChatCount)})")"/>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
</MudPaper>
|
||
|
|
|
||
|
|
@* Stated permanently, because it holds for every export and decides whether
|
||
|
|
an archive is of any use on the other computer: *@
|
||
|
|
<MudAlert Severity="Severity.Info" Dense="@true" Class="mb-3">
|
||
|
|
@T("Documents you attached, such as PDF or Word files, are not written into the archive. The chats keep the location where each document is stored, so those documents stay usable as long as the other computer can reach that location.")
|
||
|
|
</MudAlert>
|
||
|
|
|
||
|
|
@if (this.isProcessing)
|
||
|
|
{
|
||
|
|
@this.ProgressWithCancel
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Save" OnClick="@this.StartExportAsync" Disabled="@(this.isBusy || !this.IsAnythingSelected)">
|
||
|
|
@string.Format(T("Export {0} chats"), this.SelectedChatCount)
|
||
|
|
</MudButton>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@if (this.exportResult is { } result)
|
||
|
|
{
|
||
|
|
@if (!result.Success)
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Error" Dense="@true" Class="mt-3">
|
||
|
|
@result.Issue
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else if (result.Cancelled)
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Info" Dense="@true" Class="mt-3">
|
||
|
|
@T("The export was stopped. No archive was created.")
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
@* A chat missing from a backup must not pass as a success: *@
|
||
|
|
<MudAlert Severity="@(result.UnreadableChats > 0 ? Severity.Warning : Severity.Success)" Dense="@true" Class="mt-3">
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("Exported {0} chats from {1} workspaces to: {2}"), result.ExportedChats, result.ExportedWorkspaces, result.ArchivePath)
|
||
|
|
</MudText>
|
||
|
|
@if (result.IncludedFiles > 0)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("{0} files created by AI Studio, such as transcripts, were included."), result.IncludedFiles)
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
@if (result.UnreadableChats > 0)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("{0} chats could not be read and are missing from the archive. Please try the export again later."), result.UnreadableChats)
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
</MudTabPanel>
|
||
|
|
<MudTabPanel Text="@T("Import")" Icon="@Icons.Material.Filled.Unarchive" Disabled="@this.isBusy">
|
||
|
|
|
||
|
|
<MudText Typo="Typo.body2" Class="mb-2">
|
||
|
|
@T("Choose an archive to see what it contains before anything is imported.")
|
||
|
|
</MudText>
|
||
|
|
|
||
|
|
<MudStack Row="@true" AlignItems="@AlignItems.Center" Spacing="2" Class="mb-3">
|
||
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.FolderOpen" OnClick="@this.ChooseArchiveAsync" Disabled="@this.isBusy">
|
||
|
|
@T("Choose archive")
|
||
|
|
</MudButton>
|
||
|
|
@if (!string.IsNullOrWhiteSpace(this.selectedArchivePath))
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@this.selectedArchivePath
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
</MudStack>
|
||
|
|
|
||
|
|
@if (this.importPreview is { } preview)
|
||
|
|
{
|
||
|
|
@if (!preview.Success)
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Error" Dense="@true" Class="mb-3">
|
||
|
|
@preview.Issue
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<MudPaper Outlined="@true" Class="pa-3 mb-3">
|
||
|
|
<MudText Typo="Typo.body2" Class="mb-2">
|
||
|
|
@string.Format(T("Created on {0} with AI Studio {1}"), preview.Manifest.ExportedAt.ToLocalTime().ToString("g"), preview.Manifest.AppVersion)
|
||
|
|
</MudText>
|
||
|
|
|
||
|
|
@foreach (var workspace in preview.Manifest.Workspaces)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@($"{workspace.Name} ({string.Format(T("{0} chats"), workspace.Chats.Count)})")
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
|
||
|
|
@if (preview.Manifest.TemporaryChats.Count > 0)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@($"{T("Temporary chats")} ({string.Format(T("{0} chats"), preview.Manifest.TemporaryChats.Count)})")
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
</MudPaper>
|
||
|
|
|
||
|
|
<MudSelect T="ChatArchiveCollisionBehavior" @bind-Value="@this.collisionBehavior" Label="@T("When a chat already exists")" Variant="Variant.Outlined" Margin="Margin.Dense" Disabled="@this.isBusy" Class="mb-3">
|
||
|
|
<MudSelectItem T="ChatArchiveCollisionBehavior" Value="@ChatArchiveCollisionBehavior.SKIP">
|
||
|
|
@T("Keep the existing chat")
|
||
|
|
</MudSelectItem>
|
||
|
|
<MudSelectItem T="ChatArchiveCollisionBehavior" Value="@ChatArchiveCollisionBehavior.IMPORT_AS_COPY">
|
||
|
|
@T("Import it as an additional chat")
|
||
|
|
</MudSelectItem>
|
||
|
|
</MudSelect>
|
||
|
|
|
||
|
|
@if (this.isProcessing)
|
||
|
|
{
|
||
|
|
@this.ProgressWithCancel
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Download" OnClick="@this.StartImportAsync" Disabled="@(this.isBusy || !this.CanImport)">
|
||
|
|
@string.Format(T("Import {0} chats"), preview.Manifest.TotalChatCount)
|
||
|
|
</MudButton>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@if (this.importResult is { } importOutcome)
|
||
|
|
{
|
||
|
|
@if (importOutcome.Success)
|
||
|
|
{
|
||
|
|
<MudAlert Severity="@(importOutcome.Cancelled ? Severity.Info : Severity.Success)" Dense="@true" Class="mt-3">
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("Imported {0} chats into {1} workspaces."), importOutcome.ImportedChats, importOutcome.ImportedWorkspaces)
|
||
|
|
</MudText>
|
||
|
|
@if (importOutcome.Cancelled)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@T("The import was stopped. The chats imported until then were kept.")
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
@if (importOutcome.SkippedChats > 0)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("{0} chats already existed and were kept as they are."), importOutcome.SkippedChats)
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
@if (importOutcome.FailedChats > 0)
|
||
|
|
{
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("{0} chats could not be imported."), importOutcome.FailedChats)
|
||
|
|
</MudText>
|
||
|
|
}
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<MudAlert Severity="Severity.Error" Dense="@true" Class="mt-3">
|
||
|
|
@importOutcome.Issue
|
||
|
|
</MudAlert>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
</MudTabPanel>
|
||
|
|
</MudTabs>
|
||
|
|
</ExpansionPanel>
|
||
|
|
|
||
|
|
@code {
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The progress of the running export or import. Both tabs show the same thing.
|
||
|
|
/// </summary>
|
||
|
|
private RenderFragment ProgressWithCancel => @<text>
|
||
|
|
<MudProgressLinear Color="Color.Primary" Value="@this.ProgressPercentage" Class="mb-2"/>
|
||
|
|
<MudStack Row="@true" AlignItems="@AlignItems.Center" Spacing="2">
|
||
|
|
<MudText Typo="Typo.body2">
|
||
|
|
@string.Format(T("Chat {0} of {1}"), this.progress.ProcessedChats + 1, this.progress.TotalChats)
|
||
|
|
</MudText>
|
||
|
|
<MudButton Variant="Variant.Text" Color="Color.Error" StartIcon="@Icons.Material.Filled.Cancel" OnClick="@this.CancelProcessing">
|
||
|
|
@T("Cancel")
|
||
|
|
</MudButton>
|
||
|
|
</MudStack>
|
||
|
|
<MudText Typo="Typo.caption">
|
||
|
|
@T("Please stay on this page until this is done. Leaving the settings stops the run.")
|
||
|
|
</MudText>
|
||
|
|
</text>;
|
||
|
|
|
||
|
|
}
|