2026-01-09 15:49:44 +01:00
using AIStudio.Provider ;
using AIStudio.Settings ;
2025-01-05 15:11:15 +01:00
using AIStudio.Settings.DataModel ;
2026-06-09 20:11:32 +02:00
using AIStudio.Tools.Rust ;
2026-07-13 13:35:24 +02:00
using AIStudio.Tools.Services ;
using Microsoft.AspNetCore.Components ;
2025-01-05 15:11:15 +01:00
namespace AIStudio.Components.Settings ;
public partial class SettingsPanelApp : SettingsPanelBase
{
2026-07-13 13:35:24 +02:00
[Inject]
private UpdatePolicy UpdatePolicy { get ; init ; } = null !;
private UpdatePolicyMode updatePolicyMode ;
2026-08-15 14:04:45 +02:00
private bool CannotUpdateItself => this . updatePolicyMode is UpdatePolicyMode . FLATPAK or UpdatePolicyMode . MANAGED_INSTALLATION or UpdatePolicyMode . UNSUPPORTED_INSTALLATION_LOCATION or UpdatePolicyMode . DEVELOPMENT ;
private UpdateInterval DisplayedUpdateInterval => this . CannotUpdateItself
2026-07-13 13:35:24 +02:00
? UpdateInterval . NO_CHECK
: this . SettingsManager . ConfigurationData . App . UpdateInterval ;
2026-08-15 14:04:45 +02:00
private UpdateInstallation DisplayedUpdateInstallation => this . CannotUpdateItself
2026-07-13 13:35:24 +02:00
? UpdateInstallation . MANUAL
: this . SettingsManager . ConfigurationData . App . UpdateInstallation ;
private string UpdateIntervalHelp => this . updatePolicyMode switch
{
UpdatePolicyMode . ENTERPRISE_DISABLED => T ( "Your organization has disabled update checks and installations." ),
UpdatePolicyMode . FLATPAK => T ( "AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app." ),
2026-08-16 12:18:53 +02:00
UpdatePolicyMode . MANAGED_INSTALLATION => T ( "This installation does not check for updates itself. Contact the person or organization that installed AI Studio for update information." ),
2026-08-15 14:04:45 +02:00
UpdatePolicyMode . UNSUPPORTED_INSTALLATION_LOCATION => T ( "AI Studio cannot update itself from its current location, so it does not check for updates." ),
UpdatePolicyMode . DEVELOPMENT => T ( "Development builds do not check for updates." ),
2026-07-13 13:35:24 +02:00
_ => T ( "How often should we check for app updates?" )
};
private string UpdateInstallationHelp => this . updatePolicyMode switch
{
UpdatePolicyMode . ENTERPRISE_DISABLED => T ( "This setting has no effect while updates are disabled by your organization." ),
2026-08-16 12:18:53 +02:00
UpdatePolicyMode . FLATPAK => T ( "AI Studio cannot install updates when running as a Flatpak. Update it using the Flatpak source or bundle from which you installed it." ),
UpdatePolicyMode . MANAGED_INSTALLATION => T ( "AI Studio cannot install updates into this installation. Contact the person or organization that installed it for new versions." ),
UpdatePolicyMode . UNSUPPORTED_INSTALLATION_LOCATION => T ( "AI Studio cannot install updates into its current installation location. Install new versions yourself." ),
2026-08-15 14:04:45 +02:00
UpdatePolicyMode . DEVELOPMENT => T ( "Development builds do not install updates." ),
2026-07-13 13:35:24 +02:00
_ => T ( "Should updates be installed automatically or manually?" )
};
2026-08-15 14:04:45 +02:00
private bool IsUpdateIntervalLocked () => this . updatePolicyMode is UpdatePolicyMode . ENTERPRISE_DISABLED || this . CannotUpdateItself ||
2026-07-13 13:35:24 +02:00
ManagedConfiguration . TryGet ( x => x . App , x => x . UpdateInterval , out var meta ) && meta . IsLocked ;
2026-08-15 14:04:45 +02:00
private bool IsUpdateInstallationLocked () => this . updatePolicyMode is UpdatePolicyMode . ENTERPRISE_DISABLED || this . CannotUpdateItself ||
2026-07-13 13:35:24 +02:00
ManagedConfiguration . TryGet ( x => x . App , x => x . UpdateInstallation , out var meta ) && meta . IsLocked ;
protected override async Task OnInitializedAsync ()
{
2026-07-18 17:42:38 +02:00
this . ApplyFilters ([], [ Event . CONFIGURATION_CHANGED , Event . GLOBAL_SHORTCUT_CHANGED ]);
2026-07-13 13:35:24 +02:00
await base . OnInitializedAsync ();
this . updatePolicyMode = this . UpdatePolicy . CurrentMode ;
}
protected override async Task ProcessIncomingMessage < T >( ComponentBase ? sendingComponent , Event triggeredEvent , T ? data ) where T : default
{
if ( triggeredEvent is Event . CONFIGURATION_CHANGED )
this . updatePolicyMode = this . UpdatePolicy . CurrentMode ;
2026-07-18 17:42:38 +02:00
if ( triggeredEvent is Event . GLOBAL_SHORTCUT_CHANGED )
this . StateHasChanged ();
2026-07-13 13:35:24 +02:00
await base . ProcessIncomingMessage ( sendingComponent , triggeredEvent , data );
}
2026-06-09 20:11:32 +02:00
private ConfigurationShortcutData VoiceRecordingShortcut => new ()
{
Id = Shortcut . VOICE_RECORDING_TOGGLE ,
Value = () => this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecording ,
ValueUpdate = shortcut => this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecording = shortcut ,
DisplayName = () => this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecordingDisplayName ,
DisplaySource = () => this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecordingDisplaySource ,
DisplayUpdate = this . UpdateShortcutVoiceRecordingDisplay ,
};
2026-02-07 22:59:41 +01:00
private async Task GenerateEncryptionSecret ()
{
var secret = EnterpriseEncryption . GenerateSecret ();
2026-08-02 21:41:12 +02:00
await this . RustService . CopyText2Clipboard ( secret );
2026-02-07 22:59:41 +01:00
}
2026-03-21 18:05:06 +01:00
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 . ")}" ;
}
2026-02-07 22:59:41 +01:00
2026-01-09 15:49:44 +01:00
private IEnumerable < ConfigurationSelectData < string >> GetFilteredTranscriptionProviders ()
{
yield return new ( T ( "Disable dictation and transcription" ), string . Empty );
var minimumLevel = this . SettingsManager . GetMinimumConfidenceLevel ( Tools . Components . APP_SETTINGS );
2026-08-12 21:57:58 +02:00
foreach ( var provider in this . SettingsManager . GetAllTranscriptionProviders ())
2026-01-09 15:49:44 +01:00
{
if ( provider . UsedLLMProvider . GetConfidence ( this . SettingsManager ). Level >= minimumLevel )
yield return new ( provider . Name , provider . Id );
}
}
2026-08-25 12:46:10 +02:00
private TranscriptionProvider ? GetTranscriptionProvider ( string providerId )
{
var provider = this . SettingsManager . GetTranscriptionProviderById ( providerId );
return provider == TranscriptionProvider . NONE ? null : provider ;
}
2025-01-05 15:11:15 +01:00
private void UpdatePreviewFeatures ( PreviewVisibility previewVisibility )
{
this . SettingsManager . ConfigurationData . App . PreviewVisibility = previewVisibility ;
2026-02-20 12:40:38 +01:00
var filtered = previewVisibility . FilterPreviewFeatures ( this . SettingsManager . ConfigurationData . App . EnabledPreviewFeatures );
filtered . UnionWith ( this . GetPluginContributedPreviewFeatures ());
this . SettingsManager . ConfigurationData . App . EnabledPreviewFeatures = filtered ;
}
private HashSet < PreviewFeatures > GetPluginContributedPreviewFeatures ()
{
2026-08-08 18:35:46 +02:00
// Several configuration plugins may contribute at the same time, e.g. one preview feature
// for the whole organization and another one for a single department:
2026-02-20 12:40:38 +01:00
if ( ManagedConfiguration . TryGet ( x => x . App , x => x . EnabledPreviewFeatures , out var meta ) && meta . HasPluginContribution )
2026-08-08 18:35:46 +02:00
return meta . PluginContributions . Values . SelectMany ( contribution => contribution ). Where ( x => ! x . IsReleased ()). ToHashSet ();
2026-02-20 12:40:38 +01:00
return [];
}
private bool IsPluginContributedPreviewFeature ( PreviewFeatures feature )
{
if ( feature . IsReleased ())
return false ;
if (! ManagedConfiguration . TryGet ( x => x . App , x => x . EnabledPreviewFeatures , out var meta ) || ! meta . HasPluginContribution )
return false ;
2026-08-08 18:35:46 +02:00
return meta . PluginContributions . Values . Any ( contribution => contribution . Contains ( feature ));
2026-02-20 12:40:38 +01:00
}
private HashSet < PreviewFeatures > GetSelectedPreviewFeatures ()
{
var enabled = this . SettingsManager . ConfigurationData . App . EnabledPreviewFeatures . Where ( x => ! x . IsReleased ()). ToHashSet ();
enabled . UnionWith ( this . GetPluginContributedPreviewFeatures ());
return enabled ;
}
2026-05-31 18:46:54 +02:00
private string GetExternalHttpCustomRootCertificateAllowedHostsText ()
{
return string . Join ( Environment . NewLine , this . SettingsManager . ConfigurationData . App . ExternalHttpCustomRootCertificateAllowedHosts . Order ( StringComparer . OrdinalIgnoreCase ));
}
private bool AreExternalHttpCustomRootCertificateDetailsDisabled ()
{
return ! this . SettingsManager . ConfigurationData . App . ExternalHttpCustomRootCertificatesEnabled ;
}
private void UpdateExternalHttpCustomRootCertificateAllowedHosts ( string updatedText )
{
var patterns = updatedText
. Split ([ '\r' , '\n' , ';' , ',' ], StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
. Where ( pattern => ! string . IsNullOrWhiteSpace ( pattern ))
. ToHashSet ( StringComparer . OrdinalIgnoreCase );
this . SettingsManager . ConfigurationData . App . ExternalHttpCustomRootCertificateAllowedHosts = patterns ;
}
2026-02-20 12:40:38 +01:00
private void UpdateEnabledPreviewFeatures ( HashSet < PreviewFeatures > selectedFeatures )
{
selectedFeatures . UnionWith ( this . GetPluginContributedPreviewFeatures ());
this . SettingsManager . ConfigurationData . App . EnabledPreviewFeatures = selectedFeatures ;
2025-01-05 15:11:15 +01:00
}
2025-05-02 11:50:14 +02:00
2026-06-09 20:11:32 +02:00
private void UpdateShortcutVoiceRecordingDisplay ( string displayName , string displaySource )
{
this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecordingDisplayName = displayName ;
this . SettingsManager . ConfigurationData . App . ShortcutVoiceRecordingDisplaySource = displaySource ;
}
2025-05-02 11:50:14 +02:00
private async Task UpdateLangBehaviour ( LangBehavior behavior )
{
this . SettingsManager . ConfigurationData . App . LanguageBehavior = behavior ;
await this . MessageBus . SendMessage < bool >( this , Event . PLUGINS_RELOADED );
}
private async Task UpdateManuallySelectedLanguage ( Guid pluginId )
{
this . SettingsManager . ConfigurationData . App . LanguagePluginId = pluginId ;
await this . MessageBus . SendMessage < bool >( this , Event . PLUGINS_RELOADED );
}
2026-07-13 13:35:24 +02:00
}