diff --git a/app/MindWork AI Studio/Components/MSGComponentBase.cs b/app/MindWork AI Studio/Components/MSGComponentBase.cs index 3e1462a1..d2ff9d84 100644 --- a/app/MindWork AI Studio/Components/MSGComponentBase.cs +++ b/app/MindWork AI Studio/Components/MSGComponentBase.cs @@ -100,7 +100,7 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus Event.PLUGINS_RELOADED, }; - this.MessageBus.ApplyFilters(this, filterComponents, eventsList.ToArray()); + this.MessageBus.ApplyFilters(this, filterComponents, eventsList.ToHashSet()); } protected virtual void DisposeResources() diff --git a/app/MindWork AI Studio/Pages/Information.razor b/app/MindWork AI Studio/Pages/Information.razor index a859a142..b7b9aea4 100644 --- a/app/MindWork AI Studio/Pages/Information.razor +++ b/app/MindWork AI Studio/Pages/Information.razor @@ -1,6 +1,5 @@ @attribute [Route(Routes.ABOUT)] @using AIStudio.Tools.PluginSystem -@using AIStudio.Tools.Services @inherits MSGComponentBase
@@ -85,7 +84,7 @@ @T("AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available.") - @foreach (var env in EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.Where(e => e.IsActive)) + @foreach (var env in this.enterpriseEnvironments.Where(e => e.IsActive)) { } - @foreach (var env in EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.Where(e => e.IsActive)) + @foreach (var env in this.enterpriseEnvironments.Where(e => e.IsActive)) { var matchingPlugin = this.FindManagedConfigurationPlugin(env.ConfigurationId); if (matchingPlugin is null) diff --git a/app/MindWork AI Studio/Pages/Information.razor.cs b/app/MindWork AI Studio/Pages/Information.razor.cs index 1f3d946e..b9172217 100644 --- a/app/MindWork AI Studio/Pages/Information.razor.cs +++ b/app/MindWork AI Studio/Pages/Information.razor.cs @@ -75,14 +75,16 @@ public partial class Information : MSGComponentBase .Where(x => x.Type is PluginType.CONFIGURATION) .OfType() .ToList(); + + private List enterpriseEnvironments = EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.ToList(); private sealed record DatabaseDisplayInfo(string Label, string Value); private readonly List databaseDisplayInfo = new(); - private static bool HasAnyActiveEnvironment => EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.Any(e => e.IsActive); + private bool HasAnyActiveEnvironment => this.enterpriseEnvironments.Any(e => e.IsActive); - private bool HasAnyLoadedEnterpriseConfigurationPlugin => EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS + private bool HasAnyLoadedEnterpriseConfigurationPlugin => this.enterpriseEnvironments .Where(e => e.IsActive) .Any(env => this.FindManagedConfigurationPlugin(env.ConfigurationId) is not null); @@ -94,7 +96,7 @@ public partial class Information : MSGComponentBase { get { - return HasAnyActiveEnvironment switch + return this.HasAnyActiveEnvironment switch { // Case 1: No enterprise config and no plugin - no details available false when this.configPlugins.Count == 0 => false, @@ -115,7 +117,10 @@ public partial class Information : MSGComponentBase protected override async Task OnInitializedAsync() { + this.ApplyFilters([], [ Event.ENTERPRISE_ENVIRONMENTS_CHANGED ]); await base.OnInitializedAsync(); + + this.RefreshEnterpriseConfigurationState(); this.osLanguage = await this.RustService.ReadUserLanguage(); this.logPaths = await this.RustService.GetLogPaths(); @@ -139,10 +144,8 @@ public partial class Information : MSGComponentBase switch (triggeredEvent) { case Event.PLUGINS_RELOADED: - this.configPlugins = PluginFactory.AvailablePlugins - .Where(x => x.Type is PluginType.CONFIGURATION) - .OfType() - .ToList(); + case Event.ENTERPRISE_ENVIRONMENTS_CHANGED: + this.RefreshEnterpriseConfigurationState(); await this.InvokeAsync(this.StateHasChanged); break; } @@ -152,6 +155,16 @@ public partial class Information : MSGComponentBase #endregion + private void RefreshEnterpriseConfigurationState() + { + this.configPlugins = PluginFactory.AvailablePlugins + .Where(x => x.Type is PluginType.CONFIGURATION) + .OfType() + .ToList(); + + this.enterpriseEnvironments = EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.ToList(); + } + private async Task DeterminePandocVersion() { this.pandocInstallation = await Pandoc.CheckAvailabilityAsync(this.RustService, false); diff --git a/app/MindWork AI Studio/Tools/Event.cs b/app/MindWork AI Studio/Tools/Event.cs index 6e899a79..f13d5ead 100644 --- a/app/MindWork AI Studio/Tools/Event.cs +++ b/app/MindWork AI Studio/Tools/Event.cs @@ -11,6 +11,7 @@ public enum Event STARTUP_PLUGIN_SYSTEM, STARTUP_COMPLETED, STARTUP_ENTERPRISE_ENVIRONMENT, + ENTERPRISE_ENVIRONMENTS_CHANGED, PLUGINS_RELOADED, SHOW_ERROR, SHOW_WARNING, diff --git a/app/MindWork AI Studio/Tools/MessageBus.cs b/app/MindWork AI Studio/Tools/MessageBus.cs index 6f27da87..f7feb24a 100644 --- a/app/MindWork AI Studio/Tools/MessageBus.cs +++ b/app/MindWork AI Studio/Tools/MessageBus.cs @@ -33,10 +33,10 @@ public sealed class MessageBus /// That's you, the receiver. /// A list of components for which you want to receive messages. Use an empty list to receive messages from all components. /// A list of events for which you want to receive messages. - public void ApplyFilters(IMessageBusReceiver receiver, ComponentBase[] filterComponents, Event[] events) + public void ApplyFilters(IMessageBusReceiver receiver, ComponentBase[] filterComponents, HashSet events) { this.componentFilters[receiver] = filterComponents; - this.componentEvents[receiver] = events; + this.componentEvents[receiver] = events.ToArray(); } public void RegisterComponent(IMessageBusReceiver receiver) diff --git a/app/MindWork AI Studio/Tools/MessageBusExtensions.cs b/app/MindWork AI Studio/Tools/MessageBusExtensions.cs index 7956c27e..36d8b71e 100644 --- a/app/MindWork AI Studio/Tools/MessageBusExtensions.cs +++ b/app/MindWork AI Studio/Tools/MessageBusExtensions.cs @@ -11,6 +11,6 @@ public static class MessageBusExtensions public static void ApplyFilters(this IMessageBusReceiver component, ComponentBase[] components, Event[] events) { - MessageBus.INSTANCE.ApplyFilters(component, components, events); + MessageBus.INSTANCE.ApplyFilters(component, components, events.ToHashSet()); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Services/EnterpriseEnvironmentService.cs b/app/MindWork AI Studio/Tools/Services/EnterpriseEnvironmentService.cs index 0d2f2aa1..4d38eb15 100644 --- a/app/MindWork AI Studio/Tools/Services/EnterpriseEnvironmentService.cs +++ b/app/MindWork AI Studio/Tools/Services/EnterpriseEnvironmentService.cs @@ -8,6 +8,8 @@ public sealed class EnterpriseEnvironmentService(ILogger(null, Event.ENTERPRISE_ENVIRONMENTS_CHANGED); } catch (Exception e) { logger.LogError(e, "An error occurred while updating the enterprise environment."); } } + + private static List BuildNormalizedSnapshot(IEnumerable environments) + { + return environments + .Where(environment => environment.IsActive) + .Select(environment => new EnterpriseEnvironmentSnapshot( + environment.ConfigurationId, + NormalizeServerUrl(environment.ConfigurationServerUrl), + environment.ETag?.ToString())) + .OrderBy(environment => environment.ConfigurationId) + .ToList(); + } + + private static string NormalizeServerUrl(string serverUrl) + { + return serverUrl.Trim().TrimEnd('/'); + } } \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md b/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md index db925ca1..2da8017c 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md @@ -10,6 +10,7 @@ - Improved the profile selection for assistants and the chat. You can now explicitly choose between the app default profile, no profile, or a specific profile. - Improved the performance by caching the OS language detection and requesting the user language only once per app start. - Improved the chat performance by reducing unnecessary UI updates, making chats smoother and more responsive, especially in longer conversations. +- Improved the information page so enterprise configuration details now refresh live when your organization's configuration changes. - Improved the workspace loading experience: when opening the chat for the first time, your workspaces now appear faster and load step by step in the background, with placeholder rows so the app feels responsive right away. - Improved the reliability of the global voice recording shortcut so it stays available more consistently. - Improved the user-language logging by limiting language detection logs to a single entry per app start.