Added backups of all data, restorable on another computer (#1008)

Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
j-erlerandThorsten Sommer authored and GitHub committed 2026-10-15 16:42:02 +02:00
1 parent ab45580473
commit 936043319c
144 files changed
+10417 -424

No files matched your search

@@ -58,6 +58,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
[Inject]
private DataSourceEmbeddingService DataSourceEmbeddingService { get; init; } = null!;
[Inject]
private DataRestoreService DataRestoreService { get; init; } = null!;
[Inject]
private CircuitStateService CircuitState { get; init; } = null!;
@@ -82,6 +85,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
private bool settingsWriteProtectionWarningShown;
private readonly SemaphoreSlim mandatoryInfoDialogSemaphore = new(1, 1);
private readonly SemaphoreSlim promptInjectionDialogSemaphore = new(1, 1);
private readonly SemaphoreSlim dataRestorePendingDialogSemaphore = new(1, 1);
private DataSourceEmbeddingOverview embeddingOverview = new(DataSourceEmbeddingState.COMPLETED, 0, 0, 0);
private IReadOnlyCollection<NavBarItem> navItems = [];
@@ -94,6 +98,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
{
this.NavigationManager.RegisterLocationChangingHandler(this.OnLocationChanging);
this.MediaTranscriptionService.StateChanged += this.OnMediaImportStateChanged;
this.DataRestoreService.StateChanged += this.OnDataRestoreStateChanged;
//
// We use the Tauri API (Rust) to get the data and config directories
@@ -391,7 +396,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
case Event.STARTUP_COMPLETED:
this.startupCompleted = true;
this.EnsureMandatoryInfosAcceptedAsync().Observe($"{nameof(MainLayout)}: mandatory infos after the startup");
this.ShowStartupDialogsAsync().Observe($"{nameof(MainLayout)}: dialogs after the startup");
break;
case Event.RAG_EMBEDDING_STATUS_CHANGED:
@@ -640,6 +645,70 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
this.StateHasChanged();
}
/// <summary>
/// Shows what the user has to see once the plugins started: the mandatory infos first, then how a
/// restore of a backup went.
/// </summary>
private async Task ShowStartupDialogsAsync()
{
await this.EnsureMandatoryInfosAcceptedAsync();
await this.ShowDataRestoreReportAsync();
await this.ShowDataRestorePendingDialogAsync();
}
/// <summary>
/// Asks for the restart as soon as a restore is prepared.
/// </summary>
private void OnDataRestoreStateChanged()
{
if (this.DataRestoreService.IsRestorePending)
this.InvokeAsync(this.ShowDataRestorePendingDialogAsync).Observe($"{nameof(MainLayout)}: asking for the restart which applies a restore");
}
/// <summary>
/// Blocks AI Studio while a prepared restore waits for the restart, since whatever changes until
/// then would be lost.
/// </summary>
private async Task ShowDataRestorePendingDialogAsync()
{
if (!await this.dataRestorePendingDialogSemaphore.WaitAsync(0))
return;
try
{
await this.DataRestoreService.StartupStateLoaded;
if (!this.DataRestoreService.IsRestorePending)
return;
var dialogReference = await this.DialogService.ShowAsync<DataRestorePendingDialog>(T("Restore of a Backup"), DialogOptions.BLOCKING_FULLSCREEN);
await dialogReference.Result;
}
finally
{
this.dataRestorePendingDialogSemaphore.Release();
}
}
/// <summary>
/// Tells how the runtime applied a restore at this start, and what remains to do.
/// </summary>
private async Task ShowDataRestoreReportAsync()
{
await this.DataRestoreService.StartupStateLoaded;
if (this.DataRestoreService.Report is not { } report)
return;
var dialogParameters = new DialogParameters<DataRestoreReportDialog>
{
{ x => x.Report, report },
{ x => x.OpenPoints, await this.DataRestoreService.CollectOpenPointsAsync() },
};
var dialogReference = await this.DialogService.ShowAsync<DataRestoreReportDialog>(T("Restore of a Backup"), dialogParameters, DialogOptions.FULLSCREEN);
await dialogReference.Result;
this.DataRestoreService.ForgetReport();
}
private async Task EnsureMandatoryInfosAcceptedAsync()
{
if (!await this.mandatoryInfoDialogSemaphore.WaitAsync(0))
@@ -722,9 +791,11 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
public void Dispose()
{
this.MediaTranscriptionService.StateChanged -= this.OnMediaImportStateChanged;
this.DataRestoreService.StateChanged -= this.OnDataRestoreStateChanged;
this.CircuitState.ConnectionRestored -= this.OnConnectionRestored;
this.MessageBus.Unregister(this);
this.mandatoryInfoDialogSemaphore.Dispose();
this.dataRestorePendingDialogSemaphore.Dispose();
}
#endregion