Improved enterprise update policies & Flatpak support (#853)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (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, nsis) (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,updater, appimage) (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,app,updater, dmg) (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, nsis) (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,updater, appimage) (push) Blocked by required conditions
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) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-07-13 13:35:24 +02:00
1 parent 5890b3734a
commit 2f81546cfe
20 files changed
+346 -56

No files matched your search

@@ -3001,6 +3001,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1059411425"]
-- Do you want to show preview features in the app?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1118505044"] = "Do you want to show preview features in the app?"
-- AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1190632518"] = "AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app."
-- Voice recording shortcut
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"] = "Voice recording shortcut"
@@ -3043,9 +3046,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1890416390"]
-- Which preview features would you like to enable?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898060643"] = "Which preview features would you like to enable?"
-- This setting has no effect while updates are disabled by your organization.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898114759"] = "This setting has no effect while updates are disabled by your organization."
-- Select the language for the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1907446663"] = "Select the language for the app."
-- Your organization has disabled update checks and installations.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1909339369"] = "Your organization has disabled update checks and installations."
-- 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.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2013281167"] = "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."
@@ -3064,6 +3073,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2341504363"]
-- Update installation method
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T237706157"] = "Update installation method"
-- AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T244540698"] = "AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution."
-- Language
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] = "Language"
@@ -6286,6 +6298,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Update from v{0
-- Install later
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Install later"
-- Close
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T3448155331"] = "Close"
-- Show me the latest release page
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T59688848"] = "Show me the latest release page"
-- Create new workspace
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Create new workspace"
@@ -6661,6 +6679,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Copies the confi
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat."
-- Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1402243995"] = "Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio."
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library."
@@ -6766,6 +6787,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Configuration or
-- Configuration slot:
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Configuration slot:"
-- AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254976975"] = "AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub."
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "This library is used to determine the language of the operating system. This is necessary to set the language of the user interface."
@@ -7018,6 +7042,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T864851737"] = "Axum is used to p
-- For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T870640199"] = "For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose."
-- How to update
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T906183311"] = "How to update"
-- Install Pandoc
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T986578435"] = "Install Pandoc"
@@ -7423,6 +7450,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3612390107
-- Toggle the sidebar: show the workspaces next to the chat when desired
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137"] = "Toggle the sidebar: show the workspaces next to the chat when desired"
-- Updates disabled by your organization
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4048970098"] = "Updates disabled by your organization"
-- 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"
@@ -1,6 +1,7 @@
@using AIStudio.Settings
@using AIStudio.Settings.DataModel
@using AIStudio.Tools.Rust
@using AIStudio.Tools.Services
@inherits SettingsPanelBase
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Apps" HeaderText="@T("App Options")">
@@ -15,8 +16,8 @@
<ConfigurationOption OptionDescription="@T("Save energy?")" LabelOn="@T("Energy saving is enabled")" LabelOff="@T("Energy saving is disabled")" State="@(() => this.SettingsManager.ConfigurationData.App.IsSavingEnergy)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.IsSavingEnergy = updatedState)" OptionHelp="@T("When enabled, streamed content from the AI is updated once every third second. When disabled, streamed content will be updated as soon as it is available.")"/>
<ConfigurationOption OptionDescription="@T("Enable spellchecking?")" LabelOn="@T("Spellchecking is enabled")" LabelOff="@T("Spellchecking is disabled")" State="@(() => this.SettingsManager.ConfigurationData.App.EnableSpellchecking)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.EnableSpellchecking = updatedState)" OptionHelp="@T("When enabled, spellchecking will be active in all input fields. Depending on your operating system, errors may not be visually highlighted, but right-clicking may still offer possible corrections.")"/>
<ConfigurationSlider T="int" OptionDescription="@T("Request timeout")" Min="@ExternalHttpClientTimeout.MIN_HTTP_CLIENT_TIMEOUT_SECONDS" Max="@ExternalHttpClientTimeout.MAX_HTTP_CLIENT_TIMEOUT_SECONDS" Step="60" Unit="@T("seconds")" Value="@(() => this.SettingsManager.ConfigurationData.App.HttpClientTimeoutSeconds)" ValueUpdate="@(updatedValue => this.SettingsManager.ConfigurationData.App.HttpClientTimeoutSeconds = updatedValue)" OptionHelp="@T("How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.HttpClientTimeoutSeconds, 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("Check for updates")" SelectedValue="@(() => this.DisplayedUpdateInterval)" Data="@ConfigurationSelectDataFactory.GetManagedUpdateIntervalData(this.DisplayedUpdateInterval)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInterval = selectedValue)" OptionHelp="@this.UpdateIntervalHelp" IsLocked="@this.IsUpdateIntervalLocked"/>
<ConfigurationSelect OptionDescription="@T("Update installation method")" SelectedValue="@(() => this.DisplayedUpdateInstallation)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviourData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateInstallation = selectedValue)" OptionHelp="@this.UpdateInstallationHelp" IsLocked="@this.IsUpdateInstallationLocked"/>
<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"/>
@@ -2,11 +2,62 @@ using AIStudio.Provider;
using AIStudio.Settings;
using AIStudio.Settings.DataModel;
using AIStudio.Tools.Rust;
using AIStudio.Tools.Services;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Components.Settings;
public partial class SettingsPanelApp : SettingsPanelBase
{
[Inject]
private UpdatePolicy UpdatePolicy { get; init; } = null!;
private UpdatePolicyMode updatePolicyMode;
private UpdateInterval DisplayedUpdateInterval => this.updatePolicyMode is UpdatePolicyMode.FLATPAK
? UpdateInterval.NO_CHECK
: this.SettingsManager.ConfigurationData.App.UpdateInterval;
private UpdateInstallation DisplayedUpdateInstallation => this.updatePolicyMode is UpdatePolicyMode.FLATPAK
? 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."),
_ => 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."),
UpdatePolicyMode.FLATPAK => T("AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution."),
_ => T("Should updates be installed automatically or manually?")
};
private bool IsUpdateIntervalLocked() => this.updatePolicyMode is UpdatePolicyMode.ENTERPRISE_DISABLED or UpdatePolicyMode.FLATPAK ||
ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInterval, out var meta) && meta.IsLocked;
private bool IsUpdateInstallationLocked() => this.updatePolicyMode is UpdatePolicyMode.ENTERPRISE_DISABLED or UpdatePolicyMode.FLATPAK ||
ManagedConfiguration.TryGet(x => x.App, x => x.UpdateInstallation, out var meta) && meta.IsLocked;
protected override async Task OnInitializedAsync()
{
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
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;
await base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
}
private ConfigurationShortcutData VoiceRecordingShortcut => new()
{
Id = Shortcut.VOICE_RECORDING_TOGGLE,
@@ -121,4 +172,4 @@ public partial class SettingsPanelApp : SettingsPanelBase
this.SettingsManager.ConfigurationData.App.LanguagePluginId = pluginId;
await this.MessageBus.SendMessage<bool>(this, Event.PLUGINS_RELOADED);
}
}
}
@@ -0,0 +1,19 @@
@inherits MSGComponentBase
<MudDialog>
<DialogContent>
<MudJustifiedText Typo="Typo.body1">
@this.Message
</MudJustifiedText>
</DialogContent>
<DialogActions>
@if (!string.IsNullOrWhiteSpace(this.ReleaseUrl))
{
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.ReleaseUrl" Target="_blank">
@T("Show me the latest release page")
</MudButton>
}
<MudButton OnClick="@this.Close" Variant="Variant.Filled">
@T("Close")
</MudButton>
</DialogActions>
</MudDialog>
@@ -0,0 +1,19 @@
using AIStudio.Components;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs;
public partial class UpdateInstructionsDialog : MSGComponentBase
{
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!;
[Parameter]
public string Message { get; set; } = string.Empty;
[Parameter]
public string? ReleaseUrl { get; set; }
private void Close() => this.MudDialog.Close();
}
@@ -29,6 +29,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
private UpdatePolicy UpdatePolicy { get; init; } = null!;
[Inject]
private AIJobService AIJobService { get; init; } = null!;
@@ -186,6 +189,8 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
switch (triggeredEvent)
{
case Event.INSTALL_UPDATE:
if (!this.UpdatePolicy.AllowsInstallations)
break;
this.performingUpdate = true;
this.StateHasChanged();
break;
@@ -371,6 +376,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
private async Task ShowUpdateDialog()
{
if (!this.UpdatePolicy.AllowsInstallations)
return;
if(this.currentUpdateResponse is null)
return;
@@ -397,6 +405,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
var dialogResult = await dialogReference.Result;
if (dialogResult is null || dialogResult.Canceled)
return;
if (!this.UpdatePolicy.AllowsInstallations)
return;
this.performingUpdate = true;
this.StateHasChanged();
@@ -1,5 +1,6 @@
@attribute [Route(Routes.ABOUT)]
@using AIStudio.Tools.PluginSystem
@using AIStudio.Tools.Services
@inherits MSGComponentBase
<div class="inner-scrolling-context">
@@ -53,7 +54,7 @@
<MudText Typo="Typo.body1">
@this.WorkingDirectory
</MudText>
<MudCopyClipboardButton TooltipMessage="@(T("Copies the working directory to the clipboard"))" StringContent="@this.runtimeInfo.WorkingDirectory"/>
<MudCopyClipboardButton TooltipMessage="@(T("Copies the working directory to the clipboard"))" StringContent="@this.RuntimeInfo.WorkingDirectory"/>
</div>
</MudListItem>
<MudListItem T="string" Icon="@Icons.Material.Filled.InsertDriveFile">
@@ -61,7 +62,7 @@
<MudText Typo="Typo.body1">
@this.ExecutablePath
</MudText>
<MudCopyClipboardButton TooltipMessage="@(T("Copies the executable path to the clipboard"))" StringContent="@this.runtimeInfo.ExecutablePath"/>
<MudCopyClipboardButton TooltipMessage="@(T("Copies the executable path to the clipboard"))" StringContent="@this.RuntimeInfo.ExecutablePath"/>
</div>
</MudListItem>
@if (OperatingSystem.IsLinux())
@@ -193,7 +194,7 @@
</MudList>
<MudStack Row="true">
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="@this.CheckForUpdate">
@T("Check for updates")
@(this.updatePolicyMode is UpdatePolicyMode.SELF_UPDATE ? T("Check for updates") : T("How to update"))
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Default" StartIcon="@Icons.Material.Filled.Download" OnClick="@(async () => await this.ShowPandocDialog())">
@this.PandocButtonText
@@ -28,6 +28,12 @@ public partial class Information : MSGComponentBase
[Inject]
private ISnackbar Snackbar { get; init; } = null!;
[Inject]
private UpdatePolicy UpdatePolicy { get; init; } = null!;
[Inject]
private RuntimeInfoResponse RuntimeInfo { get; init; }
[Inject]
private DatabaseClientProvider DatabaseClientProvider { get; init; } = null!;
@@ -42,7 +48,7 @@ public partial class Information : MSGComponentBase
private string osLanguage = string.Empty;
private string osUserName = string.Empty;
private RuntimeInfoResponse runtimeInfo;
private UpdatePolicyMode updatePolicyMode;
private static string VersionApp => $"MindWork AI Studio: v{META_DATA.Version} (commit {META_DATA.AppCommitHash}, build {META_DATA.BuildNum}, {META_DATA_ARCH.Architecture.ToRID().ToUserFriendlyName()})";
@@ -54,13 +60,13 @@ public partial class Information : MSGComponentBase
private string OSUserName => $"{T("Username provided by the OS")}: '{this.osUserName}'";
private string WorkingDirectory => $"{T("Working directory")}: {this.runtimeInfo.WorkingDirectory}";
private string WorkingDirectory => $"{T("Working directory")}: {this.RuntimeInfo.WorkingDirectory}";
private string ExecutablePath => $"{T("Executable path")}: {this.runtimeInfo.ExecutablePath}";
private string ExecutablePath => $"{T("Executable path")}: {this.RuntimeInfo.ExecutablePath}";
private string LinuxPackageType => $"{T("Linux package")}: {this.LinuxPackageTypeDisplayName}";
private string LinuxPackageTypeDisplayName => this.runtimeInfo.LinuxPackageType switch
private string LinuxPackageTypeDisplayName => this.RuntimeInfo.LinuxPackageType switch
{
"appimage" => "AppImage",
"flatpak" => "Flatpak",
@@ -162,7 +168,7 @@ public partial class Information : MSGComponentBase
this.osLanguage = await this.RustService.ReadUserLanguage();
this.osUserName = await this.RustService.ReadUserName();
this.runtimeInfo = await this.RustService.GetRuntimeInfo();
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
this.logPaths = await this.RustService.GetLogPaths();
await this.RefreshVectorStoreInfo(CancellationToken.None);
@@ -185,6 +191,7 @@ public partial class Information : MSGComponentBase
case Event.PLUGINS_RELOADED:
case Event.ENTERPRISE_ENVIRONMENTS_CHANGED:
case Event.CONFIGURATION_CHANGED:
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
this.RefreshEnterpriseConfigurationState();
await this.InvokeAsync(this.StateHasChanged);
break;
@@ -604,6 +611,26 @@ public partial class Information : MSGComponentBase
private async Task CheckForUpdate()
{
await this.MessageBus.SendMessage<bool>(this, Event.USER_SEARCH_FOR_UPDATE);
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
if (this.updatePolicyMode is UpdatePolicyMode.SELF_UPDATE)
{
await this.MessageBus.SendMessage<bool>(this, Event.USER_SEARCH_FOR_UPDATE);
return;
}
var parameters = new DialogParameters<UpdateInstructionsDialog>();
if (this.updatePolicyMode is UpdatePolicyMode.ENTERPRISE_DISABLED)
{
parameters.Add(x => x.Message, T("Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio."));
}
else if (this.updatePolicyMode is UpdatePolicyMode.FLATPAK)
{
parameters.Add(x => x.Message, T("AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub."));
parameters.Add(x => x.ReleaseUrl, "https://github.com/MindWorkAI/AI-Studio/releases/latest");
}
else
return;
await this.DialogService.ShowAsync<UpdateInstructionsDialog>(T("How to update"), parameters, DialogOptions.FULLSCREEN);
}
}
@@ -200,7 +200,10 @@ CONFIG["DATA_SOURCES"] = {}
CONFIG["SETTINGS"] = {}
-- Configure the update check interval:
-- Allowed values are: NO_CHECK, ONCE_STARTUP, HOURLY, DAILY, WEEKLY
-- Allowed values are: NO_CHECK, DISABLE_UPDATES, ONCE_STARTUP, HOURLY, DAILY, WEEKLY
-- NO_CHECK disables automatic checks, but users can still check and install updates manually.
-- DISABLE_UPDATES is intended for enterprise configurations and disables all update checks
-- and installations. It is not offered as a selectable option in the normal app settings.
-- CONFIG["SETTINGS"]["DataApp.UpdateInterval"] = "NO_CHECK"
-- Configure how updates are installed:
@@ -3003,6 +3003,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1059411425"]
-- Do you want to show preview features in the app?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1118505044"] = "Möchten Sie Vorschaufunktionen in der App anzeigen lassen?"
-- AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1190632518"] = "AI Studio kann bei Ausführung als Flatpak nicht nach Updates suchen. Updates werden außerhalb der App verwaltet."
-- Voice recording shortcut
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"] = "Tastaturkurzbefehl für Sprachaufnahme"
@@ -3045,9 +3048,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1890416390"]
-- Which preview features would you like to enable?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898060643"] = "Welche Vorschaufunktionen möchten Sie aktivieren?"
-- This setting has no effect while updates are disabled by your organization.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898114759"] = "Diese Einstellung hat keine Auswirkungen, solange Updates von Ihrer Organisation deaktiviert sind."
-- Select the language for the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1907446663"] = "Wählen Sie die Sprache für die App aus."
-- Your organization has disabled update checks and installations.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1909339369"] = "Ihre Organisation hat die Suche nach Updates und deren Installation deaktiviert."
-- 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.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2013281167"] = "Wenn diese Option aktiviert ist, werden zusätzliche Optionen für die Administration angezeigt. Diese Optionen sind für IT-Mitarbeitende vorgesehen, um organisationsweite Einstellungen zu verwalten, z. B. Anbieter für eine gesamte Organisation zu konfigurieren und zu exportieren."
@@ -3066,6 +3075,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2341504363"]
-- Update installation method
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T237706157"] = "Installationsmethode für Updates"
-- AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T244540698"] = "AI Studio kann keine Updates installieren, wenn es als Flatpak ausgeführt wird. Verwenden Sie die von Ihrer Flatpak-Distribution bereitgestellte Methode zur Aktualisierung."
-- Language
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] = "Sprache"
@@ -6288,6 +6300,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Aktualisieren v
-- Install later
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Später installieren"
-- Close
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T3448155331"] = "Schließen"
-- Show me the latest release page
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T59688848"] = "Zeig mir die Seite mit der neuesten Version"
-- Create new workspace
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Neuen Arbeitsbereich erstellen"
@@ -6663,6 +6681,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Kopiert den Slot
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "Diese Bibliothek wird verwendet, um PDF-Dateien zu lesen. Das ist zum Beispiel notwendig, um PDFs als Datenquelle für einen Chat zu nutzen."
-- Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1402243995"] = "Updates werden von Ihrer Organisation verwaltet. Wenn Sie Fragen zur Aktualisierung von AI Studio haben, wenden Sie sich an Ihre IT-Abteilung."
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "Diese Bibliothek wird verwendet, um die MudBlazor-Bibliothek zu erweitern. Sie stellt zusätzliche Komponenten bereit, die nicht Teil der MudBlazor-Bibliothek sind."
@@ -6768,6 +6789,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Ursprung der Kon
-- Configuration slot:
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Slot der Konfiguration:"
-- AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254976975"] = "AI Studio kann sich nicht selbst aktualisieren, wenn es als Flatpak installiert ist. Ein Eintrag auf Flathub ist geplant. Bis dahin finden Sie die neueste Version auf GitHub."
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "Diese Bibliothek wird verwendet, um die Sprache des Betriebssystems zu erkennen. Dies ist notwendig, um die Sprache der Benutzeroberfläche einzustellen."
@@ -7020,6 +7044,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T864851737"] = "Axum wird verwend
-- For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T870640199"] = "Für einige Datenübertragungen müssen wir die Daten in Base64 kodieren. Diese Rust-Bibliothek eignet sich dafür hervorragend."
-- How to update
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T906183311"] = "Update-Anleitung "
-- Install Pandoc
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T986578435"] = "Pandoc installieren"
@@ -7425,6 +7452,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3612390107
-- Toggle the sidebar: show the workspaces on demand next to the chat
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137"] = "Seitenleiste umschalten: Arbeitsbereiche bei Bedarf neben dem Chat anzeigen"
-- Updates disabled by your organization
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4048970098"] = "Updates wurden von Ihrer Organisation deaktiviert"
-- 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."
@@ -3003,6 +3003,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1059411425"]
-- Do you want to show preview features in the app?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1118505044"] = "Do you want to show preview features in the app?"
-- AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1190632518"] = "AI Studio cannot check for updates when running as a Flatpak. Updates are managed outside the app."
-- Voice recording shortcut
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"] = "Voice recording shortcut"
@@ -3045,9 +3048,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1890416390"]
-- Which preview features would you like to enable?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898060643"] = "Which preview features would you like to enable?"
-- This setting has no effect while updates are disabled by your organization.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1898114759"] = "This setting has no effect while updates are disabled by your organization."
-- Select the language for the app.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1907446663"] = "Select the language for the app."
-- Your organization has disabled update checks and installations.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1909339369"] = "Your organization has disabled update checks and installations."
-- 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.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2013281167"] = "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."
@@ -3066,6 +3075,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2341504363"]
-- Update installation method
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T237706157"] = "Update installation method"
-- AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T244540698"] = "AI Studio cannot install updates when running as a Flatpak. Use the update method provided by your Flatpak distribution."
-- Language
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591284123"] = "Language"
@@ -6288,6 +6300,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Update from v{0
-- Install later
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Install later"
-- Close
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T3448155331"] = "Close"
-- Show me the latest release page
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEINSTRUCTIONSDIALOG::T59688848"] = "Show me the latest release page"
-- Create new workspace
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Create new workspace"
@@ -6663,6 +6681,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Copies the confi
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat."
-- Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1402243995"] = "Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio."
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library."
@@ -6768,6 +6789,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Configuration or
-- Configuration slot:
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Configuration slot:"
-- AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254976975"] = "AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub."
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "This library is used to determine the language of the operating system. This is necessary to set the language of the user interface."
@@ -7020,6 +7044,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T864851737"] = "Axum is used to p
-- For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose.
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T870640199"] = "For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose."
-- How to update
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T906183311"] = "How to update"
-- Install Pandoc
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T986578435"] = "Install Pandoc"
@@ -7425,6 +7452,9 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3612390107
-- Toggle the sidebar: show the workspaces on demand next to the chat
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137"] = "Toggle the sidebar: show the workspaces on demand next to the chat"
-- Updates disabled by your organization
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T4048970098"] = "Updates disabled by your organization"
-- 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"
+4
View File
@@ -6,6 +6,7 @@ using AIStudio.Tools.AIJobs;
using AIStudio.Tools.AssistantSessions;
using AIStudio.Tools.PluginSystem;
using AIStudio.Tools.PluginSystem.Assistants;
using AIStudio.Tools.Rust;
using AIStudio.Tools.Services;
using Microsoft.AspNetCore.Server.Kestrel.Core;
@@ -88,6 +89,7 @@ internal sealed class Program
return;
}
var runtimeInfo = await rust.GetRuntimeInfo();
var builder = WebApplication.CreateBuilder();
builder.WebHost.ConfigureKestrel(kestrelServerOptions =>
{
@@ -127,6 +129,7 @@ internal sealed class Program
builder.Services.AddSingleton(new MudTheme());
builder.Services.AddSingleton(MessageBus.INSTANCE);
builder.Services.AddSingleton(rust);
builder.Services.AddSingleton(typeof(RuntimeInfoResponse), runtimeInfo);
builder.Services.AddMudMarkdownClipboardService<MarkdownClipboardService>();
builder.Services.AddSingleton<SettingsManager>();
builder.Services.AddSingleton<ThreadSafeRandom>();
@@ -134,6 +137,7 @@ internal sealed class Program
builder.Services.AddSingleton<AssistantSessionService>();
builder.Services.AddSingleton<VoiceRecordingAvailabilityService>();
builder.Services.AddSingleton<AssistantPluginInstallService>();
builder.Services.AddSingleton<UpdatePolicy>();
builder.Services.AddSingleton<DataSourceService>();
builder.Services.AddScoped<PandocAvailabilityService>();
builder.Services.AddTransient<HTMLParser>();
@@ -74,6 +74,15 @@ public static class ConfigurationSelectDataFactory
yield return new (TB("Check every week"), UpdateInterval.WEEKLY);
}
public static IEnumerable<ConfigurationSelectData<UpdateInterval>> GetManagedUpdateIntervalData(UpdateInterval currentValue)
{
if (currentValue is UpdateInterval.DISABLE_UPDATES)
yield return new(TB("Updates disabled by your organization"), UpdateInterval.DISABLE_UPDATES);
foreach (var option in GetUpdateIntervalData())
yield return option;
}
public static IEnumerable<ConfigurationSelectData<UpdateInstallation>> GetUpdateBehaviourData()
{
yield return new(TB("Install updates manually"), UpdateInstallation.MANUAL);
@@ -3,6 +3,7 @@ namespace AIStudio.Settings.DataModel;
public enum UpdateInterval
{
NO_CHECK,
DISABLE_UPDATES,
ONCE_STARTUP,
HOURLY,
DAILY,
@@ -0,0 +1,23 @@
using AIStudio.Settings;
using AIStudio.Settings.DataModel;
using AIStudio.Tools.Rust;
namespace AIStudio.Tools.Services;
public sealed class UpdatePolicy(SettingsManager settingsManager, RuntimeInfoResponse runtimeInfo)
{
public UpdatePolicyMode CurrentMode => settingsManager.ConfigurationData.App.UpdateInterval is UpdateInterval.DISABLE_UPDATES
? UpdatePolicyMode.ENTERPRISE_DISABLED
: runtimeInfo.LinuxPackageType switch
{
"flatpak" => UpdatePolicyMode.FLATPAK,
_ => UpdatePolicyMode.SELF_UPDATE
};
public bool AllowsManualChecks => this.CurrentMode is UpdatePolicyMode.SELF_UPDATE;
public bool AllowsAutomaticChecks => this.CurrentMode is UpdatePolicyMode.SELF_UPDATE &&
settingsManager.ConfigurationData.App.UpdateInterval is not UpdateInterval.NO_CHECK;
public bool AllowsInstallations => this.CurrentMode is UpdatePolicyMode.SELF_UPDATE;
}
@@ -0,0 +1,8 @@
namespace AIStudio.Tools.Services;
public enum UpdatePolicyMode
{
SELF_UPDATE,
FLATPAK,
ENTERPRISE_DISABLED
}
@@ -16,15 +16,15 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
private readonly SettingsManager settingsManager;
private readonly MessageBus messageBus;
private readonly RustService rust;
private readonly UpdatePolicy updatePolicy;
private readonly ILogger<UpdateService> logger;
private TimeSpan updateInterval;
public UpdateService(MessageBus messageBus, SettingsManager settingsManager, RustService rust, ILogger<UpdateService> logger)
public UpdateService(MessageBus messageBus, SettingsManager settingsManager, RustService rust, UpdatePolicy updatePolicy, ILogger<UpdateService> logger)
{
this.settingsManager = settingsManager;
this.messageBus = messageBus;
this.rust = rust;
this.updatePolicy = updatePolicy;
this.logger = logger;
this.messageBus.RegisterComponent(this);
@@ -41,42 +41,21 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
while (!stoppingToken.IsCancellationRequested && !IS_INITIALIZED)
await Task.Delay(TimeSpan.FromSeconds(3), stoppingToken);
//
// Set the update interval based on the user's settings.
//
this.updateInterval = this.settingsManager.ConfigurationData.App.UpdateInterval switch
{
UpdateInterval.NO_CHECK => Timeout.InfiniteTimeSpan,
UpdateInterval.ONCE_STARTUP => Timeout.InfiniteTimeSpan,
UpdateInterval.HOURLY => TimeSpan.FromHours(1),
UpdateInterval.DAILY => TimeSpan.FromDays(1),
UpdateInterval.WEEKLY => TimeSpan.FromDays(7),
_ => TimeSpan.FromHours(1)
};
//
// When the user doesn't want to check for updates, we can
// return early.
//
if(this.settingsManager.ConfigurationData.App.UpdateInterval is UpdateInterval.NO_CHECK)
return;
//
// Check for updates at the beginning. The user aspects this when the app
// is started.
//
await this.CheckForUpdate();
//
// Start the update loop. This will check for updates based on the
// user's settings.
//
DateTimeOffset? lastAutomaticCheck = null;
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(this.updateInterval, stoppingToken);
await this.CheckForUpdate();
var interval = this.GetCurrentUpdateInterval();
if (this.updatePolicy.AllowsAutomaticChecks &&
(
lastAutomaticCheck is null ||
interval != Timeout.InfiniteTimeSpan && DateTimeOffset.UtcNow - lastAutomaticCheck >= interval)
)
{
await this.CheckForUpdate();
lastAutomaticCheck = DateTimeOffset.UtcNow;
}
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
@@ -97,7 +76,8 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
switch (triggeredEvent)
{
case Event.USER_SEARCH_FOR_UPDATE:
await this.CheckForUpdate(notifyUserWhenNoUpdate: true);
if (this.updatePolicy.AllowsManualChecks)
await this.CheckForUpdate(notifyUserWhenNoUpdate: true);
break;
}
}
@@ -143,6 +123,9 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
if (!isDevEnvironment && this.settingsManager.ConfigurationData.App.UpdateInstallation is UpdateInstallation.AUTOMATIC)
{
if (!this.updatePolicy.AllowsInstallations)
return;
try
{
await this.messageBus.SendMessage<bool>(null, Event.INSTALL_UPDATE);
@@ -174,6 +157,16 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
}
}
}
private TimeSpan GetCurrentUpdateInterval() => this.settingsManager.ConfigurationData.App.UpdateInterval switch
{
UpdateInterval.ONCE_STARTUP => Timeout.InfiniteTimeSpan,
UpdateInterval.HOURLY => TimeSpan.FromHours(1),
UpdateInterval.DAILY => TimeSpan.FromDays(1),
UpdateInterval.WEEKLY => TimeSpan.FromDays(7),
_ => Timeout.InfiniteTimeSpan
};
public static void SetBlazorDependencies(ISnackbar snackbar)
{
@@ -1,5 +1,6 @@
# v26.7.3, build 245 (2026-07-xx xx:xx UTC)
- Improved the "My Tasks Assistant": you can now provide one or more documents in addition to text or use documents alone when asking to identify tasks.
- Improved update guidance for Flatpak installations and added an enterprise option that lets organizations manage updates entirely through their IT department.
- Fixed an issue that could leave AI Studio unresponsive after waking the computer from sleep.
- Fixed enterprise configuration plugins from Windows-created ZIP files not loading correctly on Linux when the ZIP contained plugin files inside a folder.
- Upgraded Rust to v1.97.0.