Added config option for start page (#704)
Some checks are pending
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Read metadata (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage deb updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Blocked by required conditions

This commit is contained in:
Thorsten Sommer 2026-03-21 18:05:06 +01:00 committed by GitHub
parent df50fdb8b8
commit a2bd67eda3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 436 additions and 32 deletions

View File

@ -2269,6 +2269,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"]
-- Select preview features -- Select preview features
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "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. -- Select the desired behavior for the navigation bar.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "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 -- Administration settings are visible
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "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? -- Save energy?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "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 -- Energy saving is disabled
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "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 -- Preview feature visibility
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "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 -- 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" 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 -- No key is sending the input
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "No key is sending the input" UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "No key is sending the input"
-- Navigation never expands, no tooltips -- Navigation never expands, no tooltips
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "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 -- Store chats automatically
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "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 -- Install updates manually
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "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 -- 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" 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 -- No minimum confidence level chosen
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "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 -- Do not specify the language
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "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 -- 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" 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 -- All preview features are hidden
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "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 -- 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" UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "When possible, use the LLM provider which was used for each chat in the first place"

View File

@ -17,6 +17,7 @@
<ConfigurationSelect OptionDescription="@T("Check for updates")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateInterval)" Data="@ConfigurationSelectDataFactory.GetUpdateIntervalData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInterval = selectedValue)" OptionHelp="@T("How often should we check for app updates?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInterval, out var meta) && meta.IsLocked"/> <ConfigurationSelect OptionDescription="@T("Check for updates")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateInterval)" Data="@ConfigurationSelectDataFactory.GetUpdateIntervalData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInterval = selectedValue)" OptionHelp="@T("How often should we check for app updates?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInterval, out var meta) && meta.IsLocked"/>
<ConfigurationSelect OptionDescription="@T("Update installation method")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateInstallation)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviourData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInstallation = selectedValue)" OptionHelp="@T("Should updates be installed automatically or manually?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInstallation, out var meta) && meta.IsLocked"/> <ConfigurationSelect OptionDescription="@T("Update installation method")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateInstallation)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviourData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInstallation = selectedValue)" OptionHelp="@T("Should updates be installed automatically or manually?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInstallation, out var meta) && meta.IsLocked"/>
<ConfigurationSelect OptionDescription="@T("Navigation bar behavior")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.NavigationBehavior)" Data="@ConfigurationSelectDataFactory.GetNavBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.NavigationBehavior = selectedValue)" OptionHelp="@T("Select the desired behavior for the navigation bar.")"/> <ConfigurationSelect OptionDescription="@T("Navigation bar behavior")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.NavigationBehavior)" Data="@ConfigurationSelectDataFactory.GetNavBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.NavigationBehavior = selectedValue)" OptionHelp="@T("Select the desired behavior for the navigation bar.")"/>
<ConfigurationSelect OptionDescription="@T("Start page")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.StartPage)" Data="@ConfigurationSelectDataFactory.GetStartPageData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.StartPage = selectedValue)" OptionHelp="@this.GetStartPageHelpText()" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.StartPage, out var meta) && meta.IsLocked"/>
<ConfigurationOption OptionDescription="@T("Show administration settings?")" LabelOn="@T("Administration settings are visible")" LabelOff="@T("Administration settings are not visible")" State="@(() => this.SettingsManager.ConfigurationData.App.ShowAdminSettings)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.ShowAdminSettings = updatedState)" OptionHelp="@T("When enabled, additional administration options become visible. These options are intended for IT staff to manage organization-wide configuration, e.g. configuring and exporting providers for an entire organization.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShowAdminSettings, out var meta) && meta.IsLocked"/> <ConfigurationOption OptionDescription="@T("Show administration settings?")" LabelOn="@T("Administration settings are visible")" LabelOff="@T("Administration settings are not visible")" State="@(() => this.SettingsManager.ConfigurationData.App.ShowAdminSettings)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.ShowAdminSettings = updatedState)" OptionHelp="@T("When enabled, additional administration options become visible. These options are intended for IT staff to manage organization-wide configuration, e.g. configuring and exporting providers for an entire organization.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShowAdminSettings, out var meta) && meta.IsLocked"/>
<ConfigurationSelect OptionDescription="@T("Preview feature visibility")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.PreviewVisibility)" Data="@ConfigurationSelectDataFactory.GetPreviewVisibility()" SelectionUpdate="@this.UpdatePreviewFeatures" OptionHelp="@T("Do you want to show preview features in the app?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.PreviewVisibility, out var meta) && meta.IsLocked"/> <ConfigurationSelect OptionDescription="@T("Preview feature visibility")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.PreviewVisibility)" Data="@ConfigurationSelectDataFactory.GetPreviewVisibility()" SelectionUpdate="@this.UpdatePreviewFeatures" OptionHelp="@T("Do you want to show preview features in the app?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.PreviewVisibility, out var meta) && meta.IsLocked"/>

View File

@ -11,6 +11,15 @@ public partial class SettingsPanelApp : SettingsPanelBase
var secret = EnterpriseEncryption.GenerateSecret(); var secret = EnterpriseEncryption.GenerateSecret();
await this.RustService.CopyText2Clipboard(this.Snackbar, secret); 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<ConfigurationSelectData<string>> GetFilteredTranscriptionProviders() private IEnumerable<ConfigurationSelectData<string>> GetFilteredTranscriptionProviders()
{ {

View File

@ -1,4 +1,5 @@
using AIStudio.Components; using AIStudio.Components;
using AIStudio.Settings.DataModel;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -10,6 +11,9 @@ public partial class Home : MSGComponentBase
{ {
[Inject] [Inject]
private HttpClient HttpClient { get; init; } = null!; private HttpClient HttpClient { get; init; } = null!;
[Inject]
private NavigationManager NavigationManager { get; init; } = null!;
private string LastChangeContent { get; set; } = string.Empty; private string LastChangeContent { get; set; } = string.Empty;
@ -27,6 +31,19 @@ public partial class Home : MSGComponentBase
_ = this.ReadLastChangeAsync(); _ = 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() private void InitializeAdvantagesItems()
{ {
this.itemsAdvantages = [ this.itemsAdvantages = [

View File

@ -146,6 +146,16 @@ CONFIG["SETTINGS"] = {}
-- Allowed values are: MANUAL, AUTOMATIC -- Allowed values are: MANUAL, AUTOMATIC
-- CONFIG["SETTINGS"]["DataApp.UpdateInstallation"] = "MANUAL" -- 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: -- Configure the user permission to add providers:
-- Allowed values are: true, false -- Allowed values are: true, false
-- CONFIG["SETTINGS"]["DataApp.AllowUserToAddProvider"] = false -- CONFIG["SETTINGS"]["DataApp.AllowUserToAddProvider"] = false

View File

@ -2271,6 +2271,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"]
-- Select preview features -- Select preview features
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Vorschaufunktionen auswählen" 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. -- 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." 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 -- Administration settings are visible
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "Die Optionen für die Administration sind sichtbar." 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? -- Save energy?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Energie sparen?" 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 -- Energy saving is disabled
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "Energiesparmodus ist deaktiviert" 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 -- Preview feature visibility
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "Sichtbarkeit der Vorschaufunktion" 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 -- 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" 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 -- 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" 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 -- 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" 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 -- Store chats automatically
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "Chats automatisch speichern" UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "Chats automatisch speichern"
@ -5916,6 +5934,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2195945406
-- Install updates manually -- Install updates manually
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "Updates manuell installieren" 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 -- 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." 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 -- No minimum confidence level chosen
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "Kein Mindestvertrauensniveau ausgewählt" 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 -- Do not specify the language
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Sprache nicht festlegen" 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 -- 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." 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 -- All preview features are hidden
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "Alle Vorschaufunktionen sind ausgeblendet" 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 -- 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." UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "Wenn möglich, verwende den LLM-Anbieter, der ursprünglich für jeden Chat verwendet wurde."

View File

@ -2271,6 +2271,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"]
-- Select preview features -- Select preview features
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "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. -- Select the desired behavior for the navigation bar.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "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 -- Administration settings are visible
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"] = "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? -- Save energy?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "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 -- Energy saving is disabled
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T716338721"] = "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 -- Preview feature visibility
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T817101267"] = "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 -- 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" 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 -- 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" 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 -- 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" 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 -- Store chats automatically
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1664293672"] = "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 -- Install updates manually
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T220653235"] = "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 -- 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" 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 -- No minimum confidence level chosen
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2828607242"] = "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 -- Do not specify the language
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "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 -- 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" 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 -- All preview features are hidden
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4289410063"] = "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 -- 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" UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "When possible, use the LLM provider which was used for each chat in the first place"

View File

@ -36,6 +36,16 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
/// The ID of the plugin that locked this configuration. /// The ID of the plugin that locked this configuration.
/// </summary> /// </summary>
public Guid LockedByConfigPluginId { get; private set; } public Guid LockedByConfigPluginId { get; private set; }
/// <summary>
/// How this setting is managed by a configuration plugin, if at all.
/// </summary>
public ManagedConfigurationMode? ManagedMode { get; private set; }
/// <summary>
/// The ID of the plugin that currently provides an editable default value.
/// </summary>
public Guid EditableDefaultByConfigPluginId { get; private set; }
/// <summary> /// <summary>
/// The default value for the configuration property. This is used when resetting the property to its default state. /// 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<TClass, TValue> : ConfigMetaBase
{ {
this.IsLocked = true; this.IsLocked = true;
this.LockedByConfigPluginId = pluginId; this.LockedByConfigPluginId = pluginId;
this.ManagedMode = ManagedConfigurationMode.LOCKED;
this.EditableDefaultByConfigPluginId = Guid.Empty;
} }
/// <summary> /// <summary>
@ -75,6 +87,9 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
{ {
this.IsLocked = false; this.IsLocked = false;
this.LockedByConfigPluginId = Guid.Empty; this.LockedByConfigPluginId = Guid.Empty;
if (this.ManagedMode is ManagedConfigurationMode.LOCKED)
this.ManagedMode = null;
this.Reset(); this.Reset();
} }
@ -85,6 +100,30 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
{ {
this.IsLocked = false; this.IsLocked = false;
this.LockedByConfigPluginId = Guid.Empty; this.LockedByConfigPluginId = Guid.Empty;
if (this.ManagedMode is ManagedConfigurationMode.LOCKED)
this.ManagedMode = null;
}
/// <summary>
/// Marks the setting as having an editable default provided by a configuration plugin.
/// </summary>
public void SetEditableDefaultConfiguration(Guid pluginId)
{
this.IsLocked = false;
this.LockedByConfigPluginId = Guid.Empty;
this.ManagedMode = ManagedConfigurationMode.EDITABLE_DEFAULT;
this.EditableDefaultByConfigPluginId = pluginId;
}
/// <summary>
/// Clears the editable-default state without changing the current value.
/// </summary>
public void ClearEditableDefaultConfiguration()
{
if (this.ManagedMode is ManagedConfigurationMode.EDITABLE_DEFAULT)
this.ManagedMode = null;
this.EditableDefaultByConfigPluginId = Guid.Empty;
} }
/// <summary> /// <summary>
@ -129,4 +168,17 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo) if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo)
propertyInfo.SetValue(configInstance, value); propertyInfo.SetValue(configInstance, value);
} }
/// <summary>
/// Gets the current value of the configuration property.
/// </summary>
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!;
}
} }

View File

@ -133,6 +133,17 @@ public static class ConfigurationSelectDataFactory
yield return new(TB("Always expand navigation"), NavBehavior.ALWAYS_EXPAND); yield return new(TB("Always expand navigation"), NavBehavior.ALWAYS_EXPAND);
} }
public static IEnumerable<ConfigurationSelectData<StartPage>> 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<ConfigurationSelectData<IconSources>> GetIconSourcesData() public static IEnumerable<ConfigurationSelectData<IconSources>> GetIconSourcesData()
{ {
foreach (var source in Enum.GetValues<IconSources>()) foreach (var source in Enum.GetValues<IconSources>())

View File

@ -51,6 +51,11 @@ public sealed class Data
/// </summary> /// </summary>
public List<Guid> EnabledPlugins { get; set; } = []; public List<Guid> EnabledPlugins { get; set; } = [];
/// <summary>
/// Metadata for managed settings that use a plugin-provided editable default.
/// </summary>
public Dictionary<string, ManagedEditableDefaultState> ManagedEditableDefaults { get; set; } = [];
/// <summary> /// <summary>
/// The next provider number to use. /// The next provider number to use.
/// </summary> /// </summary>

View File

@ -52,6 +52,11 @@ public sealed class DataApp(Expression<Func<Data, DataApp>>? configSelection = n
/// </summary> /// </summary>
public NavBehavior NavigationBehavior { get; set; } = NavBehavior.NEVER_EXPAND_USE_TOOLTIPS; public NavBehavior NavigationBehavior { get; set; } = NavBehavior.NEVER_EXPAND_USE_TOOLTIPS;
/// <summary>
/// Which page should be opened first when the app starts?
/// </summary>
public StartPage StartPage { get; set; } = ManagedConfiguration.Register(configSelection, n => n.StartPage, StartPage.HOME);
/// <summary> /// <summary>
/// The visibility setting for previews features. /// The visibility setting for previews features.
/// </summary> /// </summary>

View File

@ -0,0 +1,12 @@
namespace AIStudio.Settings.DataModel;
public enum StartPage
{
HOME,
CHAT,
ASSISTANTS,
INFORMATION,
PLUGINS,
SUPPORTERS,
SETTINGS,
}

View File

@ -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,
};
}

View File

@ -63,8 +63,10 @@ public static partial class ManagedConfiguration
if(dryRun) if(dryRun)
return successful; 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);
} }
/// <summary> /// <summary>
@ -128,8 +130,10 @@ public static partial class ManagedConfiguration
if(dryRun) if(dryRun)
return successful; 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);
} }
/// <summary> /// <summary>
@ -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);
} }
/// <summary> /// <summary>
@ -857,4 +863,91 @@ public static partial class ManagedConfiguration
return successful; return successful;
} }
private static bool HandleParsedScalarValue<TClass, TValue>(
Guid configPluginId,
bool dryRun,
bool successful,
ConfigMeta<TClass, TValue> 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<TClass, TValue>(
Expression<Func<TClass, TValue>> propertyExpression,
LuaTable settings)
{
var allowUserOverrideSettingName = $"{SettingsManager.ToSettingName(propertyExpression)}.AllowUserOverride";
if (!settings.TryGetValue(allowUserOverrideSettingName, out var allowUserOverrideValue))
return ManagedConfigurationMode.LOCKED;
if (allowUserOverrideValue.TryRead<bool>(out var allowUserOverride))
return allowUserOverride ? ManagedConfigurationMode.EDITABLE_DEFAULT : ManagedConfigurationMode.LOCKED;
if (allowUserOverrideValue.TryRead<string>(out var allowUserOverrideText) && bool.TryParse(allowUserOverrideText, out allowUserOverride))
return allowUserOverride ? ManagedConfigurationMode.EDITABLE_DEFAULT : ManagedConfigurationMode.LOCKED;
return ManagedConfigurationMode.LOCKED;
}
private static string SerializeManagedScalarValue<TValue>(TValue value) => value switch
{
null => string.Empty,
string text => text,
IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture),
_ => value.ToString() ?? string.Empty,
};
} }

View File

@ -246,68 +246,68 @@ public static partial class ManagedConfiguration
public static bool IsConfigurationLeftOver<TClass, TValue>( public static bool IsConfigurationLeftOver<TClass, TValue>(
Expression<Func<Data, TClass>> configSelection, Expression<Func<Data, TClass>> configSelection,
Expression<Func<TClass, TValue>> propertyExpression, Expression<Func<TClass, TValue>> propertyExpression,
IEnumerable<IAvailablePlugin> availablePlugins) IReadOnlyList<IAvailablePlugin> availablePlugins)
where TValue : Enum where TValue : Enum
{ {
if (!TryGet(configSelection, propertyExpression, out var configMeta)) if (!TryGet(configSelection, propertyExpression, out var configMeta))
return false; return false;
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked)
return false;
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
if (plugin is null)
{ {
configMeta.ResetLockedConfiguration(); var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
return true; if (plugin is null)
{
configMeta.ResetLockedConfiguration();
return true;
}
} }
return false; return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins);
} }
public static bool IsConfigurationLeftOver<TClass>( public static bool IsConfigurationLeftOver<TClass>(
Expression<Func<Data, TClass>> configSelection, Expression<Func<Data, TClass>> configSelection,
Expression<Func<TClass, string>> propertyExpression, Expression<Func<TClass, string>> propertyExpression,
IEnumerable<IAvailablePlugin> availablePlugins) IReadOnlyList<IAvailablePlugin> availablePlugins)
{ {
if (!TryGet(configSelection, propertyExpression, out var configMeta)) if (!TryGet(configSelection, propertyExpression, out var configMeta))
return false; return false;
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked)
return false;
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
if (plugin is null)
{ {
configMeta.ResetLockedConfiguration(); var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
return true; if (plugin is null)
{
configMeta.ResetLockedConfiguration();
return true;
}
} }
return false; return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins);
} }
// ReSharper disable MethodOverloadWithOptionalParameter // ReSharper disable MethodOverloadWithOptionalParameter
public static bool IsConfigurationLeftOver<TClass, TValue>( public static bool IsConfigurationLeftOver<TClass, TValue>(
Expression<Func<Data, TClass>> configSelection, Expression<Func<Data, TClass>> configSelection,
Expression<Func<TClass, TValue>> propertyExpression, Expression<Func<TClass, TValue>> propertyExpression,
IEnumerable<IAvailablePlugin> availablePlugins, IReadOnlyList<IAvailablePlugin> availablePlugins,
ISpanParsable<TValue>? _ = null) ISpanParsable<TValue>? _ = null)
where TValue : struct, ISpanParsable<TValue> where TValue : struct, ISpanParsable<TValue>
{ {
if (!TryGet(configSelection, propertyExpression, out var configMeta)) if (!TryGet(configSelection, propertyExpression, out var configMeta))
return false; return false;
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked) if (configMeta.LockedByConfigPluginId != Guid.Empty && configMeta.IsLocked)
return false;
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
if (plugin is null)
{ {
configMeta.ResetLockedConfiguration(); var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
return true; if (plugin is null)
{
configMeta.ResetLockedConfiguration();
return true;
}
} }
return false; return CleanupEditableDefaultState(configMeta, SettingName(propertyExpression), availablePlugins);
} }
// ReSharper restore MethodOverloadWithOptionalParameter // ReSharper restore MethodOverloadWithOptionalParameter
@ -413,4 +413,44 @@ public static partial class ManagedConfiguration
var configPath = $"{configName}.{className}.{propertyName}"; var configPath = $"{configName}.{className}.{propertyName}";
return configPath; return configPath;
} }
private static string SettingName<TClass, TValue>(Expression<Func<TClass, TValue>> 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<TClass, TValue>(
ConfigMeta<TClass, TValue> configMeta,
string settingName,
IReadOnlyList<IAvailablePlugin> 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);
}
} }

View File

@ -0,0 +1,14 @@
namespace AIStudio.Settings;
public enum ManagedConfigurationMode
{
/// <summary>
/// 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.
/// </summary>
LOCKED,
/// <summary>
/// The configuration has an editable default provided by a configuration plugin. The user can change the value of this setting.
/// </summary>
EDITABLE_DEFAULT,
}

View File

@ -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;
}

View File

@ -52,6 +52,16 @@ public sealed class SettingsManager
/// </summary> /// </summary>
public bool IsDarkMode { get; set; } public bool IsDarkMode { get; set; }
/// <summary>
/// Ensures that the startup start-page redirect is evaluated at most once per app session.
/// </summary>
public bool StartupStartPageRedirectHandled { get; set; }
/// <summary>
/// Indicates that the initial settings load attempt has completed.
/// </summary>
public bool HasCompletedInitialSettingsLoad { get; private set; }
/// <summary> /// <summary>
/// The configuration data. /// The configuration data.
/// </summary> /// </summary>
@ -67,6 +77,8 @@ public sealed class SettingsManager
var settingsSnapshot = await this.TryReadSettingsSnapshot(); var settingsSnapshot = await this.TryReadSettingsSnapshot();
if (settingsSnapshot is not null) if (settingsSnapshot is not null)
this.ConfigurationData = settingsSnapshot; this.ConfigurationData = settingsSnapshot;
this.HasCompletedInitialSettingsLoad = true;
} }
/// <summary> /// <summary>

View File

@ -111,6 +111,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
// Config: how should updates be installed? // Config: how should updates be installed?
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.UpdateInstallation, this.Id, settingsTable, dryRun); 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? // Config: allow the user to add providers?
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.AllowUserToAddProvider, this.Id, settingsTable, dryRun); ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.AllowUserToAddProvider, this.Id, settingsTable, dryRun);

View File

@ -202,6 +202,10 @@ public static partial class PluginFactory
// Check for the update installation method: // Check for the update installation method:
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UpdateInstallation, AVAILABLE_PLUGINS)) if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UpdateInstallation, AVAILABLE_PLUGINS))
wasConfigurationChanged = true; 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: // Check for users allowed to added providers:
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.AllowUserToAddProvider, AVAILABLE_PLUGINS)) if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.AllowUserToAddProvider, AVAILABLE_PLUGINS))

View File

@ -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 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 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 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. - 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 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 performance by caching the OS language detection and requesting the user language only once per app start.