Render source URL for plugins (#660)
Some checks failed
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Has been cancelled
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) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Has been cancelled
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) Has been cancelled
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) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled

This commit is contained in:
Thorsten Sommer 2026-02-10 15:23:56 +01:00 committed by GitHub
parent 891b90819b
commit ea4e3f0199
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 115 additions and 21 deletions

View File

@ -5305,6 +5305,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T158493184"] = "Internal Plugins"
-- Disabled Plugins -- Disabled Plugins
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Disabled Plugins" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Disabled Plugins"
-- Send a mail
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1999487139"] = "Send a mail"
-- Enable plugin -- Enable plugin
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Enable plugin" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Enable plugin"
@ -5317,6 +5320,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Enabled Plugins"
-- Actions -- Actions
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Actions" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Actions"
-- Open website
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Open website"
-- Settings -- Settings
UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Settings" UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Settings"
@ -6037,15 +6043,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2262604281"] = "The
-- The field DESCRIPTION does not exist or is not a valid string. -- The field DESCRIPTION does not exist or is not a valid string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "The field DESCRIPTION does not exist or is not a valid string." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "The field DESCRIPTION does not exist or is not a valid string."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2320984047"] = "The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'."
-- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X). -- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X).
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X)." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X)."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2892057533"] = "The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'."
-- The table AUTHORS is empty. At least one author must be specified. -- The table AUTHORS is empty. At least one author must be specified.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "The table AUTHORS is empty. At least one author must be specified." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "The table AUTHORS is empty. At least one author must be specified."
-- The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3165663073"] = "The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient."
-- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string. -- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string."

View File

@ -63,13 +63,33 @@
</MudStack> </MudStack>
</MudTd> </MudTd>
<MudTd> <MudTd>
@if (context is { IsInternal: false, Type: not PluginType.CONFIGURATION }) <MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
{ @if (context is { IsInternal: false, Type: not PluginType.CONFIGURATION })
var isEnabled = this.SettingsManager.IsPluginEnabled(context); {
<MudTooltip Text="@(isEnabled ? T("Disable plugin") : T("Enable plugin"))"> var isEnabled = this.SettingsManager.IsPluginEnabled(context);
<MudSwitch T="bool" Value="@isEnabled" ValueChanged="@(_ => this.PluginActivationStateChanged(context))"/> <MudTooltip Text="@(isEnabled ? T("Disable plugin") : T("Enable plugin"))">
</MudTooltip> <MudSwitch T="bool" Value="@isEnabled" ValueChanged="@(_ => this.PluginActivationStateChanged(context))"/>
} </MudTooltip>
}
@if (context is { IsInternal: false } && !string.IsNullOrWhiteSpace(context.SourceURL))
{
var sourceUrl = context.SourceURL;
var isSendingMail = IsSendingMail(sourceUrl);
if(isSendingMail)
{
<MudTooltip Text="@T("Send a mail")">
<MudIconButton Icon="@Icons.Material.Filled.Email" Href="@sourceUrl" Target="_blank" Size="Size.Medium"/>
</MudTooltip>
}
else
{
<MudTooltip Text="@T("Open website")">
<MudIconButton Icon="@Icons.Material.Filled.OpenInBrowser" Href="@sourceUrl" Target="_blank" Size="Size.Medium"/>
</MudTooltip>
}
}
</MudStack>
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>

View File

@ -50,6 +50,8 @@ public partial class Plugins : MSGComponentBase
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED); await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
} }
private static bool IsSendingMail(string sourceUrl) => sourceUrl.TrimStart().StartsWith("mailto:", StringComparison.OrdinalIgnoreCase);
#region Overrides of MSGComponentBase #region Overrides of MSGComponentBase
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default

View File

@ -30,7 +30,12 @@ AUTHORS = {"<Company Name>"}
-- The support contact for the plugin: -- The support contact for the plugin:
SUPPORT_CONTACT = "<IT Department of Company Name>" SUPPORT_CONTACT = "<IT Department of Company Name>"
-- The source URL for the plugin: -- The source URL for the plugin. Can be a HTTP(S) URL or an mailto link.
-- You may link to an internal documentation page, a Git repository, or
-- to a support or wiki page.
--
-- A mailto link could look like:
-- SOURCE_URL = "mailto:helpdesk@company.org?subject=Help"
SOURCE_URL = "<Any internal Git repository>" SOURCE_URL = "<Any internal Git repository>"
-- The categories for the plugin: -- The categories for the plugin:

View File

@ -5307,6 +5307,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T158493184"] = "Interne Plugins"
-- Disabled Plugins -- Disabled Plugins
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Deaktivierte Plugins" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Deaktivierte Plugins"
-- Send a mail
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1999487139"] = "E-Mail senden"
-- Enable plugin -- Enable plugin
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Plugin aktivieren" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Plugin aktivieren"
@ -5319,6 +5322,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Aktivierte Plugins"
-- Actions -- Actions
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Aktionen" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Aktionen"
-- Open website
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Website öffnen"
-- Settings -- Settings
UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Einstellungen" UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Einstellungen"
@ -6039,15 +6045,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2262604281"] = "Das
-- The field DESCRIPTION does not exist or is not a valid string. -- The field DESCRIPTION does not exist or is not a valid string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "Das Feld DESCRIPTION existiert nicht oder ist keine gültige Zeichenkette." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "Das Feld DESCRIPTION existiert nicht oder ist keine gültige Zeichenkette."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2320984047"] = "Das Feld SOURCE_URL ist keine gültige URL. Die URL muss mit 'http://' oder 'https://' beginnen."
-- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X). -- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X).
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "Das Feld VERSION ist keine gültige Versionsnummer. Die Versionsnummer muss als Zeichenkette im Format major.minor.patch (X.X.X) angegeben werden." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "Das Feld VERSION ist keine gültige Versionsnummer. Die Versionsnummer muss als Zeichenkette im Format major.minor.patch (X.X.X) angegeben werden."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2892057533"] = "Das Feld SOURCE_URL ist keine gültige URL. Die URL muss mit „http://“, „https://“ oder „mailto:“ beginnen."
-- The table AUTHORS is empty. At least one author must be specified. -- The table AUTHORS is empty. At least one author must be specified.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "Die Tabelle AUTHORS ist leer. Es muss mindestens ein Autor angegeben werden." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "Die Tabelle AUTHORS ist leer. Es muss mindestens ein Autor angegeben werden."
-- The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3165663073"] = "Das Feld SOURCE_URL ist keine gültige URL. Wenn die URL mit „mailto:“ beginnt, muss sie eine gültige E-Mail-Adresse als Empfänger enthalten."
-- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string. -- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "Das Feld SUPPORT_CONTACT ist leer. Der Support-Kontakt muss eine nicht-leere Zeichenkette sein." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "Das Feld SUPPORT_CONTACT ist leer. Der Support-Kontakt muss eine nicht-leere Zeichenkette sein."

View File

@ -5307,6 +5307,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T158493184"] = "Internal Plugins"
-- Disabled Plugins -- Disabled Plugins
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Disabled Plugins" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1724138133"] = "Disabled Plugins"
-- Send a mail
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T1999487139"] = "Send a mail"
-- Enable plugin -- Enable plugin
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Enable plugin" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2057806005"] = "Enable plugin"
@ -5319,6 +5322,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Enabled Plugins"
-- Actions -- Actions
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Actions" UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3865031940"] = "Actions"
-- Open website
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Open website"
-- Settings -- Settings
UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Settings" UI_TEXT_CONTENT["AISTUDIO::PAGES::SETTINGS::T1258653480"] = "Settings"
@ -6039,15 +6045,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2262604281"] = "The
-- The field DESCRIPTION does not exist or is not a valid string. -- The field DESCRIPTION does not exist or is not a valid string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "The field DESCRIPTION does not exist or is not a valid string." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T229488255"] = "The field DESCRIPTION does not exist or is not a valid string."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2320984047"] = "The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'."
-- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X). -- The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X).
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X)." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2538827536"] = "The field VERSION is not a valid version number. The version number must be formatted as string in the major.minor.patch format (X.X.X)."
-- The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2892057533"] = "The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'."
-- The table AUTHORS is empty. At least one author must be specified. -- The table AUTHORS is empty. At least one author must be specified.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "The table AUTHORS is empty. At least one author must be specified." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T2981832540"] = "The table AUTHORS is empty. At least one author must be specified."
-- The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3165663073"] = "The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient."
-- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string. -- The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string." UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINBASE::T3524814526"] = "The field SUPPORT_CONTACT is empty. The support contact must be a non-empty string."

View File

@ -332,17 +332,56 @@ public abstract partial class PluginBase : IPluginMetadata
return false; return false;
} }
if (!url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) && !url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) url = url.Trim();
if (!Uri.TryCreate(url, UriKind.Absolute, out var sourceUri))
{ {
url = string.Empty; url = string.Empty;
message = TB("The field SOURCE_URL is not a valid URL. The URL must start with 'http://' or 'https://'."); message = TB("The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'.");
return false; return false;
} }
var isHttp = sourceUri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase);
var isHttps = sourceUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase);
var isMailTo = sourceUri.Scheme.Equals(Uri.UriSchemeMailto, StringComparison.OrdinalIgnoreCase);
if (!isHttp && !isHttps && !isMailTo)
{
url = string.Empty;
message = TB("The field SOURCE_URL is not a valid URL. The URL must start with 'http://', 'https://', or 'mailto:'.");
return false;
}
if (isMailTo)
{
var recipient = ExtractMailtoRecipient(url);
if (string.IsNullOrWhiteSpace(recipient))
{
url = string.Empty;
message = TB("The field SOURCE_URL is not a valid URL. When the URL starts with 'mailto:', it must contain a valid email address as recipient.");
return false;
}
}
url = sourceUri.ToString();
message = string.Empty; message = string.Empty;
return true; return true;
} }
private static string ExtractMailtoRecipient(string rawUrl)
{
var separatorIndex = rawUrl.IndexOf(':');
if (separatorIndex < 0 || separatorIndex + 1 >= rawUrl.Length)
return string.Empty;
var schemeSpecificPart = rawUrl[(separatorIndex + 1)..];
var queryStart = schemeSpecificPart.IndexOf('?');
var recipient = queryStart >= 0
? schemeSpecificPart[..queryStart]
: schemeSpecificPart;
return recipient.Trim();
}
/// <summary> /// <summary>
/// Tries to read the categories of the plugin. /// Tries to read the categories of the plugin.
/// </summary> /// </summary>

View File

@ -5,5 +5,6 @@
- Added an option in the app settings to create an encryption secret, which is required to encrypt values (for example, API keys) in configuration plugins. This feature only shows up when administration options are enabled. - Added an option in the app settings to create an encryption secret, which is required to encrypt values (for example, API keys) in configuration plugins. This feature only shows up when administration options are enabled.
- Improved the document analysis assistant (in beta) by hiding the export functionality by default. Enable the administration options in the app settings to show and use the export functionality. This streamlines the usage for regular users. - Improved the document analysis assistant (in beta) by hiding the export functionality by default. Enable the administration options in the app settings to show and use the export functionality. This streamlines the usage for regular users.
- Improved the workspaces experience by using a different color for the delete button to avoid confusion. - Improved the workspaces experience by using a different color for the delete button to avoid confusion.
- Improved the plugins page by adding an action to open the plugin source link. The action opens website URLs in an external browser, supports `mailto:` links for direct email composition.
- Fixed an issue where manually saving chats in workspace manual-storage mode could appear unreliable during response streaming. The save button is now disabled while streaming to prevent partial saves. - Fixed an issue where manually saving chats in workspace manual-storage mode could appear unreliable during response streaming. The save button is now disabled while streaming to prevent partial saves.
- Upgraded dependencies. - Upgraded dependencies.