Keep track of the config env id to show a mismatch

This commit is contained in:
Thorsten Sommer 2026-02-19 10:08:48 +01:00
parent 99e985cb3a
commit 0378c29da5
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
5 changed files with 84 additions and 25 deletions

View File

@ -137,25 +137,46 @@
break;
case true:
<MudText Typo="Typo.body1">
@T("AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active.")
</MudText>
@if (this.HasAnyLoadedEnterpriseConfigurationPlugin)
{
<MudText Typo="Typo.body1">
@T("AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active.")
</MudText>
}
else
{
<MudText Typo="Typo.body1">
@T("AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available.")
</MudText>
}
<MudCollapse Expanded="@this.showEnterpriseConfigDetails">
@foreach (var env in EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.Where(e => e.IsActive))
{
var matchingPlugin = this.configPlugins.FirstOrDefault(p => p.Id == env.ConfigurationId);
var matchingPlugin = this.FindManagedConfigurationPlugin(env.ConfigurationId);
if (matchingPlugin is null)
{
<MudPaper Outlined="true" Class="pa-3 mt-2 mb-2">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">
<MudIcon Icon="@Icons.Material.Filled.HourglassBottom" Size="Size.Small"/>
<MudText Typo="Typo.subtitle2">@T("Waiting for the configuration plugin...")</MudText>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
<span>@T("Enterprise configuration ID:") @env.ConfigurationId</span>
<MudCopyClipboardButton TooltipMessage="@T("Copies the config ID to the clipboard")" StringContent=@env.ConfigurationId.ToString()/>
</div>
<div style="display: flex; align-items: center; gap: 8px; margin-top: 4px;">
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
<span>@T("Configuration server:") @env.ConfigurationServerUrl</span>
<MudCopyClipboardButton TooltipMessage="@T("Copies the server URL to the clipboard")" StringContent=@env.ConfigurationServerUrl/>
</div>
</MudPaper>
continue;
}
<MudPaper Outlined="true" Class="pa-3 mt-2 mb-2">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">
@if (matchingPlugin is not null)
{
<MudIcon Icon="@Icons.Material.Filled.Extension" Size="Size.Small"/>
<MudText Typo="Typo.subtitle2">@matchingPlugin.Name</MudText>
}
else
{
<MudIcon Icon="@Icons.Material.Filled.Warning" Size="Size.Small" Color="Color.Warning"/>
<MudText Typo="Typo.subtitle2">@T("ID mismatch: the plugin ID differs from the enterprise configuration ID.")</MudText>
}
<MudIcon Icon="@Icons.Material.Filled.Extension" Size="Size.Small"/>
<MudText Typo="Typo.subtitle2">@matchingPlugin.Name</MudText>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
@ -167,12 +188,16 @@
<span>@T("Configuration server:") @env.ConfigurationServerUrl</span>
<MudCopyClipboardButton TooltipMessage="@T("Copies the server URL to the clipboard")" StringContent=@env.ConfigurationServerUrl/>
</div>
@if (matchingPlugin is not null)
<div style="display: flex; align-items: center; gap: 8px; margin-top: 4px;">
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
<span>@T("Configuration plugin ID:") @matchingPlugin.Id</span>
<MudCopyClipboardButton TooltipMessage="@T("Copies the configuration plugin ID to the clipboard")" StringContent=@matchingPlugin.Id.ToString()/>
</div>
@if (this.IsManagedConfigurationIdMismatch(matchingPlugin, env.ConfigurationId))
{
<div style="display: flex; align-items: center; gap: 8px; margin-top: 4px;">
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
<span>@T("Configuration plugin ID:") @matchingPlugin.Id</span>
<MudCopyClipboardButton TooltipMessage="@T("Copies the configuration plugin ID to the clipboard")" StringContent=@matchingPlugin.Id.ToString()/>
<MudIcon Icon="@Icons.Material.Filled.Warning" Size="Size.Small" Color="Color.Warning"/>
<MudText Typo="Typo.subtitle2">@T("ID mismatch: the plugin ID differs from the enterprise configuration ID.")</MudText>
</div>
}
</MudPaper>

View File

@ -69,13 +69,20 @@ public partial class Information : MSGComponentBase
private bool showDatabaseDetails;
private List<IPluginMetadata> configPlugins = PluginFactory.AvailablePlugins.Where(x => x.Type is PluginType.CONFIGURATION).ToList();
private List<IAvailablePlugin> configPlugins = PluginFactory.AvailablePlugins
.Where(x => x.Type is PluginType.CONFIGURATION)
.OfType<IAvailablePlugin>()
.ToList();
private sealed record DatabaseDisplayInfo(string Label, string Value);
private readonly List<DatabaseDisplayInfo> databaseDisplayInfo = new();
private static bool HasAnyActiveEnvironment => EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.Any(e => e.IsActive);
private bool HasAnyLoadedEnterpriseConfigurationPlugin => EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS
.Where(e => e.IsActive)
.Any(env => this.FindManagedConfigurationPlugin(env.ConfigurationId) is not null);
/// <summary>
/// Determines whether the enterprise configuration has details that can be shown/hidden.
@ -130,7 +137,10 @@ public partial class Information : MSGComponentBase
switch (triggeredEvent)
{
case Event.PLUGINS_RELOADED:
this.configPlugins = PluginFactory.AvailablePlugins.Where(x => x.Type is PluginType.CONFIGURATION).ToList();
this.configPlugins = PluginFactory.AvailablePlugins
.Where(x => x.Type is PluginType.CONFIGURATION)
.OfType<IAvailablePlugin>()
.ToList();
await this.InvokeAsync(this.StateHasChanged);
break;
}
@ -196,6 +206,18 @@ public partial class Information : MSGComponentBase
this.showDatabaseDetails = !this.showDatabaseDetails;
}
private IAvailablePlugin? FindManagedConfigurationPlugin(Guid configurationId)
{
return this.configPlugins.FirstOrDefault(plugin => plugin.ManagedConfigurationId == configurationId)
// Backward compatibility for already downloaded plugins without ManagedConfigurationId.
?? this.configPlugins.FirstOrDefault(plugin => plugin.ManagedConfigurationId is null && plugin.Id == configurationId);
}
private bool IsManagedConfigurationIdMismatch(IAvailablePlugin plugin, Guid configurationId)
{
return plugin.ManagedConfigurationId == configurationId && plugin.Id != configurationId;
}
private async Task CopyStartupLogPath()
{
await this.RustService.CopyText2Clipboard(this.Snackbar, this.logPaths.LogStartupPath);

View File

@ -3,5 +3,8 @@ namespace AIStudio.Tools.PluginSystem;
public interface IAvailablePlugin : IPluginMetadata
{
public string LocalPath { get; }
public bool IsManagedByConfigServer { get; }
public Guid? ManagedConfigurationId { get; }
}

View File

@ -109,6 +109,7 @@ public static partial class PluginFactory
pluginPath.StartsWith(CONFIGURATION_PLUGINS_ROOT, StringComparison.OrdinalIgnoreCase);
var isManagedByConfigServer = false;
Guid? managedConfigurationId = null;
if (plugin is PluginConfiguration configPlugin)
{
if (configPlugin.DeployedUsingConfigServer.HasValue)
@ -123,14 +124,20 @@ public static partial class PluginFactory
// For configuration plugins, validate that the plugin ID matches the enterprise config ID
// (the directory name under which the plugin was downloaded):
if (isConfigurationPluginInConfigDirectory)
if (isConfigurationPluginInConfigDirectory && isManagedByConfigServer)
{
var directoryName = Path.GetFileName(pluginPath);
if (Guid.TryParse(directoryName, out var enterpriseConfigId) && enterpriseConfigId != plugin.Id)
LOG.LogWarning($"The configuration plugin's ID ('{plugin.Id}') does not match the enterprise configuration ID ('{enterpriseConfigId}'). These IDs should be identical. Please update the plugin's ID field to match the enterprise configuration ID.");
if (Guid.TryParse(directoryName, out var enterpriseConfigId))
{
managedConfigurationId = enterpriseConfigId;
if (enterpriseConfigId != plugin.Id)
LOG.LogWarning($"The configuration plugin's ID ('{plugin.Id}') does not match the enterprise configuration ID ('{enterpriseConfigId}'). These IDs should be identical. Please update the plugin's ID field to match the enterprise configuration ID.");
}
else
LOG.LogWarning($"Could not determine the managed configuration ID for configuration plugin '{plugin.Id}'. The plugin directory '{pluginPath}' does not end with a valid GUID.");
}
AVAILABLE_PLUGINS.Add(new PluginMetadata(plugin, pluginPath, isManagedByConfigServer));
AVAILABLE_PLUGINS.Add(new PluginMetadata(plugin, pluginPath, isManagedByConfigServer, managedConfigurationId));
}
catch (Exception e)
{

View File

@ -1,6 +1,6 @@
namespace AIStudio.Tools.PluginSystem;
public sealed class PluginMetadata(PluginBase plugin, string localPath, bool isManagedByConfigServer = false) : IAvailablePlugin
public sealed class PluginMetadata(PluginBase plugin, string localPath, bool isManagedByConfigServer = false, Guid? managedConfigurationId = null) : IAvailablePlugin
{
#region Implementation of IPluginMetadata
@ -53,6 +53,8 @@ public sealed class PluginMetadata(PluginBase plugin, string localPath, bool isM
public string LocalPath { get; } = localPath;
public bool IsManagedByConfigServer { get; } = isManagedByConfigServer;
public Guid? ManagedConfigurationId { get; } = managedConfigurationId;
#endregion
}