From a2bd67eda308a3333fb4a6832ab77d838b29ce25 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 21 Mar 2026 18:05:06 +0100 Subject: [PATCH] Added config option for start page (#704) --- .../Assistants/I18N/allTexts.lua | 30 +++++ .../Settings/SettingsPanelApp.razor | 1 + .../Settings/SettingsPanelApp.razor.cs | 9 ++ app/MindWork AI Studio/Pages/Home.razor.cs | 17 +++ .../Plugins/configuration/plugin.lua | 10 ++ .../plugin.lua | 30 +++++ .../plugin.lua | 30 +++++ app/MindWork AI Studio/Settings/ConfigMeta.cs | 52 +++++++++ .../ConfigurationSelectDataFactory.cs | 11 ++ .../Settings/DataModel/Data.cs | 5 + .../Settings/DataModel/DataApp.cs | 5 + .../Settings/DataModel/StartPage.cs | 12 ++ .../Settings/DataModel/StartPageExtensions.cs | 17 +++ .../Settings/ManagedConfiguration.Parsing.cs | 103 +++++++++++++++++- .../Settings/ManagedConfiguration.cs | 94 +++++++++++----- .../Settings/ManagedConfigurationMode.cs | 14 +++ .../Settings/ManagedEditableDefaultState.cs | 8 ++ .../Settings/SettingsManager.cs | 12 ++ .../Tools/PluginSystem/PluginConfiguration.cs | 3 + .../PluginSystem/PluginFactory.Loading.cs | 4 + .../wwwroot/changelog/v26.3.1.md | 1 + 21 files changed, 436 insertions(+), 32 deletions(-) create mode 100644 app/MindWork AI Studio/Settings/DataModel/StartPage.cs create mode 100644 app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs create mode 100644 app/MindWork AI Studio/Settings/ManagedConfigurationMode.cs create mode 100644 app/MindWork AI Studio/Settings/ManagedEditableDefaultState.cs diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index e899d79a..6d4cc501 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -2269,6 +2269,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] -- Select preview features UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Select preview features" +-- Your organization provided a default start page, but you can still change it. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Your organization provided a default start page, but you can still change it." + -- Select the desired behavior for the navigation bar. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Select the desired behavior for the navigation bar." @@ -2317,6 +2320,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] -- Administration settings are visible UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "Administration settings are visible" +-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio." + -- Save energy? UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Save energy?" @@ -2365,6 +2371,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T71162186"] = -- Energy saving is disabled UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "Energy saving is disabled" +-- Start page +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T78084670"] = "Start page" + -- Preview feature visibility UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "Preview feature visibility" @@ -5884,12 +5893,21 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1188453609 -- Show also prototype features: these are works in progress; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1245257804"] = "Show also prototype features: these are works in progress; expect bugs and missing features" +-- Settings +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1258653480"] = "Settings" + -- No key is sending the input UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "No key is sending the input" -- Navigation never expands, no tooltips UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "Navigation never expands, no tooltips" +-- Welcome +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1485461907"] = "Welcome" + +-- Assistants +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1614176092"] = "Assistants" + -- Store chats automatically UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "Store chats automatically" @@ -5914,6 +5932,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2195945406 -- Install updates manually UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "Install updates manually" +-- Plugins +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2222816203"] = "Plugins" + -- Also show features ready for release; these should be stable UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2301448762"] = "Also show features ready for release; these should be stable" @@ -5935,6 +5956,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2566503670 -- No minimum confidence level chosen UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "No minimum confidence level chosen" +-- Supporters +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2929332068"] = "Supporters" + -- Do not specify the language UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Do not specify the language" @@ -5968,9 +5992,15 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137 -- Also show features in alpha: these are in development; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4146964761"] = "Also show features in alpha: these are in development; expect bugs and missing features" +-- Information +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4256323669"] = "Information" + -- All preview features are hidden UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "All preview features are hidden" +-- Chat +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T578410699"] = "Chat" + -- When possible, use the LLM provider which was used for each chat in the first place UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "When possible, use the LLM provider which was used for each chat in the first place" diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor index cbc33d79..c5ae753f 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor @@ -17,6 +17,7 @@ + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs index 70b6d24a..a5fbc06b 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs @@ -11,6 +11,15 @@ public partial class SettingsPanelApp : SettingsPanelBase var secret = EnterpriseEncryption.GenerateSecret(); await this.RustService.CopyText2Clipboard(this.Snackbar, secret); } + + private string GetStartPageHelpText() + { + var helpText = T("Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio."); + if (!ManagedConfiguration.TryGet(x => x.App, x => x.StartPage, out var meta) || meta.ManagedMode is not ManagedConfigurationMode.EDITABLE_DEFAULT) + return helpText; + + return $"{helpText} {T("Your organization provided a default start page, but you can still change it.")}"; + } private IEnumerable> GetFilteredTranscriptionProviders() { diff --git a/app/MindWork AI Studio/Pages/Home.razor.cs b/app/MindWork AI Studio/Pages/Home.razor.cs index 04c35db6..40431683 100644 --- a/app/MindWork AI Studio/Pages/Home.razor.cs +++ b/app/MindWork AI Studio/Pages/Home.razor.cs @@ -1,4 +1,5 @@ using AIStudio.Components; +using AIStudio.Settings.DataModel; using Microsoft.AspNetCore.Components; @@ -10,6 +11,9 @@ public partial class Home : MSGComponentBase { [Inject] private HttpClient HttpClient { get; init; } = null!; + + [Inject] + private NavigationManager NavigationManager { get; init; } = null!; private string LastChangeContent { get; set; } = string.Empty; @@ -27,6 +31,19 @@ public partial class Home : MSGComponentBase _ = this.ReadLastChangeAsync(); } + protected override Task OnAfterRenderAsync(bool firstRender) + { + if (this.SettingsManager.StartupStartPageRedirectHandled || !this.SettingsManager.HasCompletedInitialSettingsLoad) + return base.OnAfterRenderAsync(firstRender); + + this.SettingsManager.StartupStartPageRedirectHandled = true; + var startPageRoute = this.SettingsManager.ConfigurationData.App.StartPage.ToRoute(); + if (!string.IsNullOrWhiteSpace(startPageRoute)) + this.NavigationManager.NavigateTo(startPageRoute, replace: true); + + return base.OnAfterRenderAsync(firstRender); + } + private void InitializeAdvantagesItems() { this.itemsAdvantages = [ diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua index 37098f77..03a9b0f4 100644 --- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua +++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua @@ -146,6 +146,16 @@ CONFIG["SETTINGS"] = {} -- Allowed values are: MANUAL, AUTOMATIC -- CONFIG["SETTINGS"]["DataApp.UpdateInstallation"] = "MANUAL" +-- Configure the page that should be opened when AI Studio starts. +-- Allowed values are: HOME, CHAT, ASSISTANTS, INFORMATION, PLUGINS, SUPPORTERS, SETTINGS +-- CONFIG["SETTINGS"]["DataApp.StartPage"] = "CHAT" +-- +-- Allow users to change the configured start page locally. +-- Allowed values are: true, false +-- When set to true, the configured start page becomes the organization default, +-- but users can still choose another start page in the app settings. +-- CONFIG["SETTINGS"]["DataApp.StartPage.AllowUserOverride"] = true + -- Configure the user permission to add providers: -- Allowed values are: true, false -- CONFIG["SETTINGS"]["DataApp.AllowUserToAddProvider"] = false diff --git a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua index 0a94f7a7..e9571a6c 100644 --- a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua @@ -2271,6 +2271,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] -- Select preview features UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Vorschaufunktionen auswählen" +-- Your organization provided a default start page, but you can still change it. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Ihre Organisation hat eine Standard-Startseite festgelegt, die Sie jedoch ändern können." + -- Select the desired behavior for the navigation bar. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Wählen Sie das gewünschte Verhalten für die Navigationsleiste aus." @@ -2319,6 +2322,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] -- Administration settings are visible UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "Die Optionen für die Administration sind sichtbar." +-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Wählen Sie aus, welche Seite AI Studio beim Start der App zuerst öffnen soll. Änderungen werden beim nächsten Start von AI Studio wirksam." + -- Save energy? UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Energie sparen?" @@ -2367,6 +2373,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T71162186"] = -- Energy saving is disabled UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "Energiesparmodus ist deaktiviert" +-- Start page +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T78084670"] = "Startseite" + -- Preview feature visibility UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "Sichtbarkeit der Vorschaufunktion" @@ -5886,12 +5895,21 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1188453609 -- Show also prototype features: these are works in progress; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1245257804"] = "Auch Prototyp-Funktionen anzeigen: Diese befinden sich noch in der Entwicklung; Fehler und fehlende Funktionen sind zu erwarten" +-- Settings +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1258653480"] = "Einstellungen" + -- No key is sending the input; you have to click the send button UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "Keine Taste sendet die Eingabe; Sie müssen auf die Schaltfläche klicken, um zu senden" -- Navigation never expands, no tooltips; there are only icons UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "Navigationsleiste wird nie erweitert, keine Tooltips; es werden nur Icons angezeigt" +-- Welcome +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1485461907"] = "Willkommen" + +-- Assistants +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1614176092"] = "Assistenten" + -- Store chats automatically UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "Chats automatisch speichern" @@ -5916,6 +5934,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2195945406 -- Install updates manually UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "Updates manuell installieren" +-- Plugins +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2222816203"] = "Plugins" + -- Also show features ready for release; these should be stable UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2301448762"] = "Auch Funktionen anzeigen, die bereit für die Veröffentlichung sind; diese sollten stabil sein." @@ -5937,6 +5958,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2566503670 -- No minimum confidence level chosen UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "Kein Mindestvertrauensniveau ausgewählt" +-- Supporters +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2929332068"] = "Unterstützer" + -- Do not specify the language UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Sprache nicht festlegen" @@ -5970,9 +5994,15 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137 -- Also show features in alpha: these are in development; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4146964761"] = "Zeige auch Funktionen im Alpha-Stadium an: Diese befinden sich in der Entwicklung; es werden Fehler und fehlende Funktionen auftreten." +-- Information +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4256323669"] = "Information" + -- All preview features are hidden UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "Alle Vorschaufunktionen sind ausgeblendet" +-- Chat +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T578410699"] = "Chat" + -- When possible, use the LLM provider which was used for each chat in the first place UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "Wenn möglich, verwende den LLM-Anbieter, der ursprünglich für jeden Chat verwendet wurde." diff --git a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua index 2849c6d2..71f6c65a 100644 --- a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua @@ -2271,6 +2271,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] -- Select preview features UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Select preview features" +-- Your organization provided a default start page, but you can still change it. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Your organization provided a default start page, but you can still change it." + -- Select the desired behavior for the navigation bar. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Select the desired behavior for the navigation bar." @@ -2319,6 +2322,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] -- Administration settings are visible UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "Administration settings are visible" +-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio." + -- Save energy? UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Save energy?" @@ -2367,6 +2373,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T71162186"] = -- Energy saving is disabled UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "Energy saving is disabled" +-- Start page +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T78084670"] = "Start page" + -- Preview feature visibility UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "Preview feature visibility" @@ -5886,12 +5895,21 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1188453609 -- Show also prototype features: these are works in progress; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1245257804"] = "Show also prototype features: these are works in progress; expect bugs and missing features" +-- Settings +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1258653480"] = "Settings" + -- No key is sending the input; you have to click the send button UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "No key is sending the input; you have to click the send button" -- Navigation never expands, no tooltips; there are only icons UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "Navigation never expands, no tooltips; there are only icons" +-- Welcome +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1485461907"] = "Welcome" + +-- Assistants +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1614176092"] = "Assistants" + -- Store chats automatically UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "Store chats automatically" @@ -5916,6 +5934,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2195945406 -- Install updates manually UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "Install updates manually" +-- Plugins +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2222816203"] = "Plugins" + -- Also show features ready for release; these should be stable UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2301448762"] = "Also show features ready for release; these should be stable" @@ -5937,6 +5958,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2566503670 -- No minimum confidence level chosen UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "No minimum confidence level chosen" +-- Supporters +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2929332068"] = "Supporters" + -- Do not specify the language UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Do not specify the language" @@ -5970,9 +5994,15 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137 -- Also show features in alpha: these are in development; expect bugs and missing features UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4146964761"] = "Also show features in alpha: these are in development; expect bugs and missing features" +-- Information +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4256323669"] = "Information" + -- All preview features are hidden UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "All preview features are hidden" +-- Chat +UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T578410699"] = "Chat" + -- When possible, use the LLM provider which was used for each chat in the first place UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "When possible, use the LLM provider which was used for each chat in the first place" diff --git a/app/MindWork AI Studio/Settings/ConfigMeta.cs b/app/MindWork AI Studio/Settings/ConfigMeta.cs index 6b81c3e8..46a248b3 100644 --- a/app/MindWork AI Studio/Settings/ConfigMeta.cs +++ b/app/MindWork AI Studio/Settings/ConfigMeta.cs @@ -36,6 +36,16 @@ public record ConfigMeta : ConfigMetaBase /// The ID of the plugin that locked this configuration. /// public Guid LockedByConfigPluginId { get; private set; } + + /// + /// How this setting is managed by a configuration plugin, if at all. + /// + public ManagedConfigurationMode? ManagedMode { get; private set; } + + /// + /// The ID of the plugin that currently provides an editable default value. + /// + public Guid EditableDefaultByConfigPluginId { get; private set; } /// /// The default value for the configuration property. This is used when resetting the property to its default state. @@ -65,6 +75,8 @@ public record ConfigMeta : ConfigMetaBase { this.IsLocked = true; this.LockedByConfigPluginId = pluginId; + this.ManagedMode = ManagedConfigurationMode.LOCKED; + this.EditableDefaultByConfigPluginId = Guid.Empty; } /// @@ -75,6 +87,9 @@ public record ConfigMeta : ConfigMetaBase { this.IsLocked = false; this.LockedByConfigPluginId = Guid.Empty; + if (this.ManagedMode is ManagedConfigurationMode.LOCKED) + this.ManagedMode = null; + this.Reset(); } @@ -85,6 +100,30 @@ public record ConfigMeta : ConfigMetaBase { this.IsLocked = false; this.LockedByConfigPluginId = Guid.Empty; + if (this.ManagedMode is ManagedConfigurationMode.LOCKED) + this.ManagedMode = null; + } + + /// + /// Marks the setting as having an editable default provided by a configuration plugin. + /// + public void SetEditableDefaultConfiguration(Guid pluginId) + { + this.IsLocked = false; + this.LockedByConfigPluginId = Guid.Empty; + this.ManagedMode = ManagedConfigurationMode.EDITABLE_DEFAULT; + this.EditableDefaultByConfigPluginId = pluginId; + } + + /// + /// Clears the editable-default state without changing the current value. + /// + public void ClearEditableDefaultConfiguration() + { + if (this.ManagedMode is ManagedConfigurationMode.EDITABLE_DEFAULT) + this.ManagedMode = null; + + this.EditableDefaultByConfigPluginId = Guid.Empty; } /// @@ -129,4 +168,17 @@ public record ConfigMeta : ConfigMetaBase if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo) propertyInfo.SetValue(configInstance, value); } + + /// + /// Gets the current value of the configuration property. + /// + public TValue GetValue() + { + var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData); + var memberExpression = this.PropertyExpression.GetMemberExpression(); + if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo && propertyInfo.GetValue(configInstance) is TValue value) + return value; + + return default!; + } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs index 0f8b9d5d..c6465e5b 100644 --- a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs +++ b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs @@ -133,6 +133,17 @@ public static class ConfigurationSelectDataFactory yield return new(TB("Always expand navigation"), NavBehavior.ALWAYS_EXPAND); } + public static IEnumerable> GetStartPageData() + { + yield return new(TB("Welcome"), StartPage.HOME); + yield return new(TB("Chat"), StartPage.CHAT); + yield return new(TB("Assistants"), StartPage.ASSISTANTS); + yield return new(TB("Information"), StartPage.INFORMATION); + yield return new(TB("Plugins"), StartPage.PLUGINS); + yield return new(TB("Supporters"), StartPage.SUPPORTERS); + yield return new(TB("Settings"), StartPage.SETTINGS); + } + public static IEnumerable> GetIconSourcesData() { foreach (var source in Enum.GetValues()) diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs index 0013fe92..d6339739 100644 --- a/app/MindWork AI Studio/Settings/DataModel/Data.cs +++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs @@ -51,6 +51,11 @@ public sealed class Data /// public List EnabledPlugins { get; set; } = []; + /// + /// Metadata for managed settings that use a plugin-provided editable default. + /// + public Dictionary ManagedEditableDefaults { get; set; } = []; + /// /// The next provider number to use. /// diff --git a/app/MindWork AI Studio/Settings/DataModel/DataApp.cs b/app/MindWork AI Studio/Settings/DataModel/DataApp.cs index a1def46f..3a62164b 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataApp.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataApp.cs @@ -52,6 +52,11 @@ public sealed class DataApp(Expression>? configSelection = n /// public NavBehavior NavigationBehavior { get; set; } = NavBehavior.NEVER_EXPAND_USE_TOOLTIPS; + /// + /// Which page should be opened first when the app starts? + /// + public StartPage StartPage { get; set; } = ManagedConfiguration.Register(configSelection, n => n.StartPage, StartPage.HOME); + /// /// The visibility setting for previews features. /// diff --git a/app/MindWork AI Studio/Settings/DataModel/StartPage.cs b/app/MindWork AI Studio/Settings/DataModel/StartPage.cs new file mode 100644 index 00000000..07b95b1a --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/StartPage.cs @@ -0,0 +1,12 @@ +namespace AIStudio.Settings.DataModel; + +public enum StartPage +{ + HOME, + CHAT, + ASSISTANTS, + INFORMATION, + PLUGINS, + SUPPORTERS, + SETTINGS, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs new file mode 100644 index 00000000..d37ca52b --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs @@ -0,0 +1,17 @@ +namespace AIStudio.Settings.DataModel; + +public static class StartPageExtensions +{ + public static string ToRoute(this StartPage startPage) => startPage switch + { + StartPage.HOME => string.Empty, + StartPage.CHAT => Routes.CHAT, + StartPage.ASSISTANTS => Routes.ASSISTANTS, + StartPage.INFORMATION => Routes.ABOUT, + StartPage.PLUGINS => Routes.PLUGINS, + StartPage.SUPPORTERS => Routes.SUPPORTERS, + StartPage.SETTINGS => Routes.SETTINGS, + + _ => string.Empty, + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs b/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs index e4cf5f2e..4b453d27 100644 --- a/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs +++ b/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs @@ -63,8 +63,10 @@ public static partial class ManagedConfiguration if(dryRun) return successful; - - return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue); + + var settingName = SettingName(propertyExpression); + var managedMode = ReadManagedConfigurationMode(propertyExpression, settings); + return HandleParsedScalarValue(configPluginId, dryRun, successful, configMeta, configuredValue, managedMode, settingName); } /// @@ -128,8 +130,10 @@ public static partial class ManagedConfiguration if(dryRun) return successful; - - return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue); + + var settingName = SettingName(propertyExpression); + var managedMode = ReadManagedConfigurationMode(propertyExpression, settings); + return HandleParsedScalarValue(configPluginId, dryRun, successful, configMeta, configuredValue, managedMode, settingName); } /// @@ -216,7 +220,9 @@ public static partial class ManagedConfiguration } } - return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue); + var settingName = SettingName(propertyExpression); + var managedMode = ReadManagedConfigurationMode(propertyExpression, settings); + return HandleParsedScalarValue(configPluginId, dryRun, successful, configMeta, configuredValue, managedMode, settingName); } /// @@ -857,4 +863,91 @@ public static partial class ManagedConfiguration return successful; } + + private static bool HandleParsedScalarValue( + Guid configPluginId, + bool dryRun, + bool successful, + ConfigMeta configMeta, + TValue configuredValue, + ManagedConfigurationMode managedMode, + string settingName) + { + if (dryRun) + return successful; + + switch (successful) + { + case true when managedMode is ManagedConfigurationMode.LOCKED: + ClearEditableDefaultState(settingName); + configMeta.ClearEditableDefaultConfiguration(); + configMeta.SetValue(configuredValue); + configMeta.LockConfiguration(configPluginId); + break; + + case true when managedMode is ManagedConfigurationMode.EDITABLE_DEFAULT: + var currentValueSerialized = SerializeManagedScalarValue(configMeta.GetValue()); + var configuredValueSerialized = SerializeManagedScalarValue(configuredValue); + + string lastAppliedValue; + if (!TryGetEditableDefaultState(settingName, out var editableDefaultState)) + { + configMeta.SetValue(configuredValue); + lastAppliedValue = configuredValueSerialized; + } + else + { + lastAppliedValue = editableDefaultState.LastAppliedValue; + if (string.Equals(currentValueSerialized, lastAppliedValue, StringComparison.Ordinal)) + { + configMeta.SetValue(configuredValue); + lastAppliedValue = configuredValueSerialized; + } + } + + SetEditableDefaultState(settingName, configPluginId, lastAppliedValue); + configMeta.UnlockConfiguration(); + configMeta.SetEditableDefaultConfiguration(configPluginId); + break; + + case false when configMeta.IsLocked && configMeta.LockedByConfigPluginId == configPluginId: + configMeta.ResetLockedConfiguration(); + break; + + case false when configMeta.ManagedMode is ManagedConfigurationMode.EDITABLE_DEFAULT + && TryGetEditableDefaultState(settingName, out var editableDefaultStateToRemove) + && editableDefaultStateToRemove.ConfigPluginId == configPluginId: + configMeta.ClearEditableDefaultConfiguration(); + ClearEditableDefaultState(settingName); + break; + } + + return successful; + } + + private static ManagedConfigurationMode ReadManagedConfigurationMode( + Expression> propertyExpression, + LuaTable settings) + { + var allowUserOverrideSettingName = $"{SettingsManager.ToSettingName(propertyExpression)}.AllowUserOverride"; + if (!settings.TryGetValue(allowUserOverrideSettingName, out var allowUserOverrideValue)) + return ManagedConfigurationMode.LOCKED; + + if (allowUserOverrideValue.TryRead(out var allowUserOverride)) + return allowUserOverride ? ManagedConfigurationMode.EDITABLE_DEFAULT : ManagedConfigurationMode.LOCKED; + + if (allowUserOverrideValue.TryRead(out var allowUserOverrideText) && bool.TryParse(allowUserOverrideText, out allowUserOverride)) + return allowUserOverride ? ManagedConfigurationMode.EDITABLE_DEFAULT : ManagedConfigurationMode.LOCKED; + + return ManagedConfigurationMode.LOCKED; + } + + private static string SerializeManagedScalarValue(TValue value) => value switch + { + null => string.Empty, + string text => text, + IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture), + + _ => value.ToString() ?? string.Empty, + }; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ManagedConfiguration.cs b/app/MindWork AI Studio/Settings/ManagedConfiguration.cs index 363cccc1..0e62f2c6 100644 --- a/app/MindWork AI Studio/Settings/ManagedConfiguration.cs +++ b/app/MindWork AI Studio/Settings/ManagedConfiguration.cs @@ -246,68 +246,68 @@ public static partial class ManagedConfiguration public static bool IsConfigurationLeftOver( Expression> configSelection, Expression> propertyExpression, - IEnumerable availablePlugins) + IReadOnlyList availablePlugins) where TValue : Enum { if (!TryGet(configSelection, propertyExpression, out var configMeta)) return false; - if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) - return false; - - var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); - if (plugin is null) + if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked) { - configMeta.ResetLockedConfiguration(); - return true; + var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); + if (plugin is null) + { + configMeta.ResetLockedConfiguration(); + return true; + } } - return false; + return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins); } public static bool IsConfigurationLeftOver( Expression> configSelection, Expression> propertyExpression, - IEnumerable availablePlugins) + IReadOnlyList availablePlugins) { if (!TryGet(configSelection, propertyExpression, out var configMeta)) return false; - if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) - return false; - - var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); - if (plugin is null) + if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked) { - configMeta.ResetLockedConfiguration(); - return true; + var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); + if (plugin is null) + { + configMeta.ResetLockedConfiguration(); + return true; + } } - return false; + return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins); } // ReSharper disable MethodOverloadWithOptionalParameter public static bool IsConfigurationLeftOver( Expression> configSelection, Expression> propertyExpression, - IEnumerable availablePlugins, + IReadOnlyList availablePlugins, ISpanParsable? _ = null) where TValue : struct, ISpanParsable { if (!TryGet(configSelection, propertyExpression, out var configMeta)) return false; - if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) - return false; - - var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); - if (plugin is null) + if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked) { - configMeta.ResetLockedConfiguration(); - return true; + var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId); + if (plugin is null) + { + configMeta.ResetLockedConfiguration(); + return true; + } } - return false; + return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins); } // ReSharper restore MethodOverloadWithOptionalParameter @@ -413,4 +413,44 @@ public static partial class ManagedConfiguration var configPath = $"{configName}.{className}.{propertyName}"; return configPath; } + + private static string SettingName(Expression> propertyExpression) => SettingsManager.ToSettingName(propertyExpression); + + private static bool TryGetEditableDefaultState(string settingName, out ManagedEditableDefaultState editableDefaultState) + { + return SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults.TryGetValue(settingName, out editableDefaultState!); + } + + private static void SetEditableDefaultState(string settingName, Guid pluginId, string lastAppliedValue) + { + SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults[settingName] = new() + { + ConfigPluginId = pluginId, + LastAppliedValue = lastAppliedValue, + }; + } + + private static bool ClearEditableDefaultState(string settingName) => SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults.Remove(settingName); + + private static bool CleanupEditableDefaultState( + ConfigMeta configMeta, + string settingName, + IReadOnlyList availablePlugins) + { + if (!TryGetEditableDefaultState(settingName, out var editableDefaultState)) + { + if (configMeta.ManagedMode is not ManagedConfigurationMode.EDITABLE_DEFAULT) + return false; + + configMeta.ClearEditableDefaultConfiguration(); + return true; + } + + var plugin = availablePlugins.FirstOrDefault(x => x.Id == editableDefaultState.ConfigPluginId); + if (plugin is not null) + return false; + + configMeta.ClearEditableDefaultConfiguration(); + return ClearEditableDefaultState(settingName); + } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ManagedConfigurationMode.cs b/app/MindWork AI Studio/Settings/ManagedConfigurationMode.cs new file mode 100644 index 00000000..324a5748 --- /dev/null +++ b/app/MindWork AI Studio/Settings/ManagedConfigurationMode.cs @@ -0,0 +1,14 @@ +namespace AIStudio.Settings; + +public enum ManagedConfigurationMode +{ + /// + /// The configuration is locked by a configuration plugin. The user cannot change the value of this setting, and it will be overridden by the plugin on each update. + /// + LOCKED, + + /// + /// The configuration has an editable default provided by a configuration plugin. The user can change the value of this setting. + /// + EDITABLE_DEFAULT, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ManagedEditableDefaultState.cs b/app/MindWork AI Studio/Settings/ManagedEditableDefaultState.cs new file mode 100644 index 00000000..8904c497 --- /dev/null +++ b/app/MindWork AI Studio/Settings/ManagedEditableDefaultState.cs @@ -0,0 +1,8 @@ +namespace AIStudio.Settings; + +public sealed class ManagedEditableDefaultState +{ + public Guid ConfigPluginId { get; init; } = Guid.Empty; + + public string LastAppliedValue { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/SettingsManager.cs b/app/MindWork AI Studio/Settings/SettingsManager.cs index 911d827f..50c8c03e 100644 --- a/app/MindWork AI Studio/Settings/SettingsManager.cs +++ b/app/MindWork AI Studio/Settings/SettingsManager.cs @@ -52,6 +52,16 @@ public sealed class SettingsManager /// public bool IsDarkMode { get; set; } + /// + /// Ensures that the startup start-page redirect is evaluated at most once per app session. + /// + public bool StartupStartPageRedirectHandled { get; set; } + + /// + /// Indicates that the initial settings load attempt has completed. + /// + public bool HasCompletedInitialSettingsLoad { get; private set; } + /// /// The configuration data. /// @@ -67,6 +77,8 @@ public sealed class SettingsManager var settingsSnapshot = await this.TryReadSettingsSnapshot(); if (settingsSnapshot is not null) this.ConfigurationData = settingsSnapshot; + + this.HasCompletedInitialSettingsLoad = true; } /// diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs index b4007b9d..99031624 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs @@ -111,6 +111,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT // Config: how should updates be installed? ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.UpdateInstallation, this.Id, settingsTable, dryRun); + + // Config: what should be the start page? + ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.StartPage, this.Id, settingsTable, dryRun); // Config: allow the user to add providers? ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.AllowUserToAddProvider, this.Id, settingsTable, dryRun); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs index be6de578..f110e766 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs @@ -202,6 +202,10 @@ public static partial class PluginFactory // Check for the update installation method: if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UpdateInstallation, AVAILABLE_PLUGINS)) wasConfigurationChanged = true; + + // Check for the start page: + if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.StartPage, AVAILABLE_PLUGINS)) + wasConfigurationChanged = true; // Check for users allowed to added providers: if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.AllowUserToAddProvider, AVAILABLE_PLUGINS)) 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 f611bcc8..ba8f5c42 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md @@ -4,6 +4,7 @@ - Added a reminder in chats and assistants that LLMs can make mistakes, helping you double-check important information more easily. - Added the ability to format your user prompt in the chat using icons instead of typing Markdown directly. - Added the ability to load a system prompt from a file when creating or editing chat templates. +- Added a start-page setting, so AI Studio can now open directly on your preferred page when the app starts. Configuration plugins can also provide and optionally lock this default for organizations. - Released the document analysis assistant after an intense testing phase. - 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.