mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 21:27:21 +00:00
Added a home page prompt for missing API keys of enterprise providers (#1056)
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
1 parent
1f8d72aa45
commit
7d35536c87
29 files changed
+920
-31
No files matched your search
@@ -12,6 +12,11 @@
|
||||
{
|
||||
<MudExpansionPanels @key="@this.expansionPanelsRenderKey" Class="mb-3" MultiExpansion="@false">
|
||||
|
||||
@foreach (var group in this.pendingUserAPIKeyGroups)
|
||||
{
|
||||
<UserAPIKeyPrompt @key="@group.ConfigPluginId" Group="@group" IsExpanded="@this.IsPanelExpanded(UserAPIKeyPanelId(group))" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(UserAPIKeyPanelId(group), isExpanded))"/>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowIntroduction)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.MenuBook" HeaderText="@T("Introduction")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION, isExpanded))">
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Services;
|
||||
using AIStudio.Tools.UserAPIKeys;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -15,13 +17,21 @@ public partial class Home : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private NavigationManager NavigationManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
private string LastChangeContent { get; set; } = string.Empty;
|
||||
|
||||
private TextItem[] itemsAdvantages = [];
|
||||
|
||||
private List<DataIntroduction> introductions = [];
|
||||
|
||||
|
||||
private IReadOnlyList<PendingUserAPIKeyGroup> pendingUserAPIKeyGroups = [];
|
||||
private Task initialReadOfPendingUserAPIKeys = Task.CompletedTask;
|
||||
private bool hasReadPendingUserAPIKeys;
|
||||
private int pendingUserAPIKeysGeneration;
|
||||
|
||||
private string expandedPanelId = string.Empty;
|
||||
private int expansionPanelsRenderKey;
|
||||
|
||||
@@ -43,19 +53,37 @@ public partial class Home : MSGComponentBase
|
||||
// Read the last change content asynchronously
|
||||
// without blocking the UI thread:
|
||||
this.ReadLastChangeAsync().Observe($"{nameof(Home)}: reading the last change");
|
||||
|
||||
// Reading the stored API keys takes a moment, so the page renders the other panels first:
|
||||
this.initialReadOfPendingUserAPIKeys = this.RefreshPendingUserAPIKeysAsync();
|
||||
await this.initialReadOfPendingUserAPIKeys;
|
||||
}
|
||||
|
||||
protected override Task OnAfterRenderAsync(bool firstRender)
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (this.SettingsManager.StartupStartPageRedirectHandled || !this.SettingsManager.HasCompletedInitialSettingsLoad)
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
return;
|
||||
|
||||
this.SettingsManager.StartupStartPageRedirectHandled = true;
|
||||
var startPageRoute = this.SettingsManager.ConfigurationData.App.StartPage.ToRoute();
|
||||
if (!string.IsNullOrWhiteSpace(startPageRoute))
|
||||
this.NavigationManager.NavigateTo(startPageRoute, replace: true);
|
||||
if (string.IsNullOrWhiteSpace(startPageRoute))
|
||||
return;
|
||||
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
//
|
||||
// The home page asks for missing API keys of the organization's providers. Stay here while
|
||||
// one is missing, so the user sees that request no matter the chosen start page. The page
|
||||
// reads the keys while it initializes; when the settings were not loaded by then, it reads
|
||||
// them now:
|
||||
//
|
||||
await this.initialReadOfPendingUserAPIKeys;
|
||||
if (!this.hasReadPendingUserAPIKeys)
|
||||
await this.RefreshPendingUserAPIKeysAsync();
|
||||
|
||||
if (this.pendingUserAPIKeyGroups.Count > 0)
|
||||
return;
|
||||
|
||||
this.NavigationManager.NavigateTo(startPageRoute, replace: true);
|
||||
}
|
||||
|
||||
private void InitializeAdvantagesItems()
|
||||
@@ -87,12 +115,14 @@ public partial class Home : MSGComponentBase
|
||||
case Event.PLUGINS_RELOADED:
|
||||
this.InitializeAdvantagesItems();
|
||||
this.RefreshIntroductionPanels();
|
||||
await this.RefreshPendingUserAPIKeysAsync();
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
this.RefreshIntroductionPanels();
|
||||
await this.RefreshPendingUserAPIKeysAsync();
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
@@ -106,7 +136,34 @@ public partial class Home : MSGComponentBase
|
||||
this.introductions = PluginFactory.GetIntroductions().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads which providers of the organization wait for the API key of the user. When the configuration
|
||||
/// plugins of these providers change, the page opens the first panel which asks for a key.
|
||||
/// </summary>
|
||||
private async Task RefreshPendingUserAPIKeysAsync()
|
||||
{
|
||||
// Which providers exist is unknown until the settings are loaded:
|
||||
if (!this.SettingsManager.HasCompletedInitialSettingsLoad)
|
||||
return;
|
||||
|
||||
// Several events may ask for a refresh at once; only the latest answer counts:
|
||||
var generation = ++this.pendingUserAPIKeysGeneration;
|
||||
var groups = await PendingUserAPIKeys.FindAsync(this.SettingsManager, this.RustService);
|
||||
if (generation != this.pendingUserAPIKeysGeneration)
|
||||
return;
|
||||
|
||||
var hasChanged = !groups.Select(group => group.ConfigPluginId).SequenceEqual(this.pendingUserAPIKeyGroups.Select(group => group.ConfigPluginId));
|
||||
this.pendingUserAPIKeyGroups = groups;
|
||||
this.hasReadPendingUserAPIKeys = true;
|
||||
if (!hasChanged)
|
||||
return;
|
||||
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
|
||||
private bool HasVisibleHomePanels =>
|
||||
this.pendingUserAPIKeyGroups.Count > 0 ||
|
||||
this.SettingsManager.ConfigurationData.App.ShowIntroduction ||
|
||||
this.introductions.Count > 0 ||
|
||||
this.SettingsManager.ConfigurationData.App.ShowLastChangelog ||
|
||||
@@ -115,6 +172,11 @@ public partial class Home : MSGComponentBase
|
||||
|
||||
private string GetDefaultExpandedPanelId()
|
||||
{
|
||||
// A missing API key keeps the providers of the organization from working, so it comes first:
|
||||
var firstPendingUserAPIKeyGroup = this.pendingUserAPIKeyGroups.FirstOrDefault();
|
||||
if (firstPendingUserAPIKeyGroup is not null)
|
||||
return UserAPIKeyPanelId(firstPendingUserAPIKeyGroup);
|
||||
|
||||
if (this.SettingsManager.ConfigurationData.App.ShowIntroduction)
|
||||
return PANEL_ID_BUILT_IN_INTRODUCTION;
|
||||
|
||||
@@ -154,6 +216,8 @@ public partial class Home : MSGComponentBase
|
||||
|
||||
private static string IntroductionPanelId(DataIntroduction introduction) => $"introduction:{introduction.Id}";
|
||||
|
||||
private static string UserAPIKeyPanelId(PendingUserAPIKeyGroup group) => $"user-api-key:{group.ConfigPluginId}";
|
||||
|
||||
private async Task ReadLastChangeAsync()
|
||||
{
|
||||
var latest = Changelog.LOGS.MaxBy(n => n.Build);
|
||||
|
||||
Reference in new issue
Block a user