mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-21 14:01:36 +00:00
Introduced additive configuration handling for managed preview features (#667)
Some checks are pending
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
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Some checks are pending
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
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
parent
ed8bd9d25c
commit
6f76c845f1
@ -14,8 +14,22 @@
|
|||||||
SelectedValuesChanged="@this.OptionChanged">
|
SelectedValuesChanged="@this.OptionChanged">
|
||||||
@foreach (var data in this.Data)
|
@foreach (var data in this.Data)
|
||||||
{
|
{
|
||||||
<MudSelectItemExtended Value="@data.Value">
|
var isLockedValue = this.IsLockedValue(data.Value);
|
||||||
@data.Name
|
<MudSelectItemExtended Value="@data.Value" Disabled="@isLockedValue" Style="@(isLockedValue ? "pointer-events:auto !important;" : null)">
|
||||||
|
@if (isLockedValue)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.FlexStart" Wrap="Wrap.NoWrap">
|
||||||
|
@* MudTooltip.RootStyle is set as a workaround for issue -> https://github.com/MudBlazor/MudBlazor/issues/10882 *@
|
||||||
|
<MudTooltip Text="@this.LockedTooltip()" Arrow="true" Placement="Placement.Right" RootStyle="display:inline-flex;">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Lock" Color="Color.Error" Size="Size.Small" Class="mr-1"/>
|
||||||
|
</MudTooltip>
|
||||||
|
@data.Name
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@data.Name
|
||||||
|
}
|
||||||
</MudSelectItemExtended>
|
</MudSelectItemExtended>
|
||||||
}
|
}
|
||||||
</MudSelectExtended>
|
</MudSelectExtended>
|
||||||
@ -28,6 +28,12 @@ public partial class ConfigurationMultiSelect<TData> : ConfigurationBaseCore
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public Action<HashSet<TData>> SelectionUpdate { get; set; } = _ => { };
|
public Action<HashSet<TData>> SelectionUpdate { get; set; } = _ => { };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a specific item is locked by a configuration plugin.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<TData, bool> IsItemLocked { get; set; } = _ => false;
|
||||||
|
|
||||||
#region Overrides of ConfigurationBase
|
#region Overrides of ConfigurationBase
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -62,4 +68,12 @@ public partial class ConfigurationMultiSelect<TData> : ConfigurationBaseCore
|
|||||||
|
|
||||||
return string.Format(T("You have selected {0} preview features."), selectedValues.Count);
|
return string.Format(T("You have selected {0} preview features."), selectedValues.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsLockedValue(TData value) => this.IsItemLocked(value);
|
||||||
|
|
||||||
|
private string LockedTooltip() =>
|
||||||
|
this.T(
|
||||||
|
"This feature is managed by your organization and has therefore been disabled.",
|
||||||
|
typeof(ConfigurationBase).Namespace,
|
||||||
|
nameof(ConfigurationBase));
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@
|
|||||||
var availablePreviewFeatures = ConfigurationSelectDataFactory.GetPreviewFeaturesData(this.SettingsManager).ToList();
|
var availablePreviewFeatures = ConfigurationSelectDataFactory.GetPreviewFeaturesData(this.SettingsManager).ToList();
|
||||||
if (availablePreviewFeatures.Count > 0)
|
if (availablePreviewFeatures.Count > 0)
|
||||||
{
|
{
|
||||||
<ConfigurationMultiSelect OptionDescription="@T("Select preview features")" SelectedValues="@(() => this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures.Where(x => !x.IsReleased()).ToHashSet())" Data="@availablePreviewFeatures" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = selectedValue)" OptionHelp="@T("Which preview features would you like to enable?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.IsLocked"/>
|
<ConfigurationMultiSelect OptionDescription="@T("Select preview features")" SelectedValues="@this.GetSelectedPreviewFeatures" Data="@availablePreviewFeatures" SelectionUpdate="@this.UpdateEnabledPreviewFeatures" OptionHelp="@T("Which preview features would you like to enable?")" IsItemLocked="@this.IsPluginContributedPreviewFeature" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.IsLocked"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,41 @@ public partial class SettingsPanelApp : SettingsPanelBase
|
|||||||
private void UpdatePreviewFeatures(PreviewVisibility previewVisibility)
|
private void UpdatePreviewFeatures(PreviewVisibility previewVisibility)
|
||||||
{
|
{
|
||||||
this.SettingsManager.ConfigurationData.App.PreviewVisibility = previewVisibility;
|
this.SettingsManager.ConfigurationData.App.PreviewVisibility = previewVisibility;
|
||||||
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = previewVisibility.FilterPreviewFeatures(this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures);
|
var filtered = previewVisibility.FilterPreviewFeatures(this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures);
|
||||||
|
filtered.UnionWith(this.GetPluginContributedPreviewFeatures());
|
||||||
|
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<PreviewFeatures> GetPluginContributedPreviewFeatures()
|
||||||
|
{
|
||||||
|
if (ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.HasPluginContribution)
|
||||||
|
return meta.PluginContribution.Where(x => !x.IsReleased()).ToHashSet();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return meta.PluginContribution.Contains(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<PreviewFeatures> GetSelectedPreviewFeatures()
|
||||||
|
{
|
||||||
|
var enabled = this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures.Where(x => !x.IsReleased()).ToHashSet();
|
||||||
|
enabled.UnionWith(this.GetPluginContributedPreviewFeatures());
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEnabledPreviewFeatures(HashSet<PreviewFeatures> selectedFeatures)
|
||||||
|
{
|
||||||
|
selectedFeatures.UnionWith(this.GetPluginContributedPreviewFeatures());
|
||||||
|
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = selectedFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
||||||
|
|||||||
@ -28,14 +28,14 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
|||||||
private Expression<Func<TClass, TValue>> PropertyExpression { get; }
|
private Expression<Func<TClass, TValue>> PropertyExpression { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the configuration is managed by a plugin and is therefore locked.
|
/// Indicates whether the configuration is locked by a configuration plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsLocked { get; private set; }
|
public bool IsLocked { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the plugin that manages this configuration. This is set when the configuration is locked.
|
/// The ID of the plugin that locked this configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid MangedByConfigPluginId { get; private set; }
|
public Guid LockedByConfigPluginId { 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.
|
||||||
@ -43,30 +43,74 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
|||||||
public required TValue Default { get; init; }
|
public required TValue Default { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the configuration state, indicating that it is managed by a specific plugin.
|
/// Indicates whether a plugin contribution is available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pluginId">The ID of the plugin that is managing this configuration.</param>
|
public bool HasPluginContribution { get; private set; }
|
||||||
public void LockManagedState(Guid pluginId)
|
|
||||||
|
/// <summary>
|
||||||
|
/// The additive value contribution provided by a configuration plugin.
|
||||||
|
/// </summary>
|
||||||
|
public TValue PluginContribution { get; private set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the plugin that provided the additive value contribution.
|
||||||
|
/// </summary>
|
||||||
|
public Guid PluginContributionByConfigPluginId { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Locks the configuration state, indicating that it is controlled by a specific plugin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pluginId">The ID of the plugin that is locking this configuration.</param>
|
||||||
|
public void LockConfiguration(Guid pluginId)
|
||||||
{
|
{
|
||||||
this.IsLocked = true;
|
this.IsLocked = true;
|
||||||
this.MangedByConfigPluginId = pluginId;
|
this.LockedByConfigPluginId = pluginId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the managed state of the configuration, allowing it to be modified again.
|
/// Resets the locked state of the configuration, allowing it to be modified again.
|
||||||
/// This will also reset the property to its default value.
|
/// This will also reset the property to its default value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ResetManagedState()
|
public void ResetLockedConfiguration()
|
||||||
{
|
{
|
||||||
this.IsLocked = false;
|
this.IsLocked = false;
|
||||||
this.MangedByConfigPluginId = Guid.Empty;
|
this.LockedByConfigPluginId = Guid.Empty;
|
||||||
this.Reset();
|
this.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unlocks the configuration state without changing the current value.
|
||||||
|
/// </summary>
|
||||||
|
public void UnlockConfiguration()
|
||||||
|
{
|
||||||
|
this.IsLocked = false;
|
||||||
|
this.LockedByConfigPluginId = Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores an additive plugin contribution.
|
||||||
|
/// </summary>
|
||||||
|
public void SetPluginContribution(TValue value, Guid pluginId)
|
||||||
|
{
|
||||||
|
this.PluginContribution = value;
|
||||||
|
this.PluginContributionByConfigPluginId = pluginId;
|
||||||
|
this.HasPluginContribution = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the additive plugin contribution without changing the current value.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearPluginContribution()
|
||||||
|
{
|
||||||
|
this.PluginContribution = default!;
|
||||||
|
this.PluginContributionByConfigPluginId = Guid.Empty;
|
||||||
|
this.HasPluginContribution = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the configuration property to its default value.
|
/// Resets the configuration property to its default value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reset()
|
private void Reset()
|
||||||
{
|
{
|
||||||
var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||||
var memberExpression = this.PropertyExpression.GetMemberExpression();
|
var memberExpression = this.PropertyExpression.GetMemberExpression();
|
||||||
|
|||||||
@ -582,6 +582,90 @@ public static partial class ManagedConfiguration
|
|||||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to process additive plugin contributions for enum set settings from a Lua table.
|
||||||
|
/// The contributed values are merged into the existing set, and the setting remains unlocked
|
||||||
|
/// so users can add additional values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||||
|
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||||
|
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||||
|
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||||
|
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||||
|
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||||
|
/// <typeparam name="TValue">The type of the property within the configuration class. It is also the type of the set
|
||||||
|
/// elements, which must be an enum.</typeparam>
|
||||||
|
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||||
|
public static bool TryProcessConfigurationWithPluginContribution<TClass, TValue>(
|
||||||
|
Expression<Func<Data, TClass>> configSelection,
|
||||||
|
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||||
|
Guid configPluginId,
|
||||||
|
LuaTable settings,
|
||||||
|
bool dryRun)
|
||||||
|
where TValue : Enum
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Handle configured enum sets (additive merge)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Check if that configuration was registered:
|
||||||
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var successful = false;
|
||||||
|
var configuredValue = new HashSet<TValue>();
|
||||||
|
|
||||||
|
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||||
|
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||||
|
configuredLuaList.Type is LuaValueType.Table &&
|
||||||
|
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||||
|
{
|
||||||
|
// Determine the length of the Lua table and prepare a set to hold the parsed values:
|
||||||
|
var len = valueTable.ArrayLength;
|
||||||
|
var set = new HashSet<TValue>(len);
|
||||||
|
|
||||||
|
// Iterate over each entry in the Lua table:
|
||||||
|
for (var index = 1; index <= len; index++)
|
||||||
|
{
|
||||||
|
// Retrieve the Lua value at the current index:
|
||||||
|
var value = valueTable[index];
|
||||||
|
|
||||||
|
// Step 2 -- try to read the Lua value as a string:
|
||||||
|
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||||
|
{
|
||||||
|
// Step 3 -- try to parse the string as the target type:
|
||||||
|
if (Enum.TryParse(typeof(TValue), configuredLuaValueText, true, out var configuredEnum))
|
||||||
|
set.Add((TValue)configuredEnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredValue = set;
|
||||||
|
successful = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun)
|
||||||
|
return successful;
|
||||||
|
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
var configInstance = configSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||||
|
var currentValue = propertyExpression.Compile().Invoke(configInstance);
|
||||||
|
var merged = new HashSet<TValue>(currentValue);
|
||||||
|
merged.UnionWith(configuredValue);
|
||||||
|
configMeta.SetValue(merged);
|
||||||
|
configMeta.SetPluginContribution(new HashSet<TValue>(configuredValue), configPluginId);
|
||||||
|
}
|
||||||
|
else if (configMeta.HasPluginContribution && configMeta.PluginContributionByConfigPluginId == configPluginId)
|
||||||
|
{
|
||||||
|
configMeta.ClearPluginContribution();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configMeta.IsLocked && configMeta.LockedByConfigPluginId == configPluginId)
|
||||||
|
configMeta.UnlockConfiguration();
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to process the configuration settings from a Lua table for string set types.
|
/// Attempts to process the configuration settings from a Lua table for string set types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -744,12 +828,12 @@ public static partial class ManagedConfiguration
|
|||||||
// Case: the setting was configured, and we could read the value successfully.
|
// Case: the setting was configured, and we could read the value successfully.
|
||||||
//
|
//
|
||||||
|
|
||||||
// Set the configured value and lock the managed state:
|
// Set the configured value and lock the configuration:
|
||||||
configMeta.SetValue(configuredValue);
|
configMeta.SetValue(configuredValue);
|
||||||
configMeta.LockManagedState(configPluginId);
|
configMeta.LockConfiguration(configPluginId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false when configMeta.IsLocked && configMeta.MangedByConfigPluginId == configPluginId:
|
case false when configMeta.IsLocked && configMeta.LockedByConfigPluginId == configPluginId:
|
||||||
//
|
//
|
||||||
// Case: the setting was configured previously, but we could not read the value successfully.
|
// Case: the setting was configured previously, but we could not read the value successfully.
|
||||||
// This happens when the setting was removed from the configuration plugin. We handle that
|
// This happens when the setting was removed from the configuration plugin. We handle that
|
||||||
@ -757,10 +841,10 @@ public static partial class ManagedConfiguration
|
|||||||
//
|
//
|
||||||
// The other case, when the setting was locked and managed by a different configuration plugin,
|
// The other case, when the setting was locked and managed by a different configuration plugin,
|
||||||
// is handled by the IsConfigurationLeftOver method, which checks if the configuration plugin
|
// is handled by the IsConfigurationLeftOver method, which checks if the configuration plugin
|
||||||
// is still available. If it is not available, it resets the managed state of the
|
// is still available. If it is not available, it resets the locked state of the
|
||||||
// configuration setting, allowing it to be reconfigured by a different plugin or left unchanged.
|
// configuration setting, allowing it to be reconfigured by a different plugin or left unchanged.
|
||||||
//
|
//
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false:
|
case false:
|
||||||
|
|||||||
@ -9,6 +9,7 @@ namespace AIStudio.Settings;
|
|||||||
public static partial class ManagedConfiguration
|
public static partial class ManagedConfiguration
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, IConfig> METADATA = new();
|
private static readonly ConcurrentDictionary<string, IConfig> METADATA = new();
|
||||||
|
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to retrieve the configuration metadata for a given configuration selection and
|
/// Attempts to retrieve the configuration metadata for a given configuration selection and
|
||||||
@ -251,13 +252,13 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,13 +273,13 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,13 +297,13 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,13 +320,13 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,13 +341,38 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a plugin contribution is left over from a configuration plugin that is no longer available.
|
||||||
|
/// If so, it clears the contribution and returns true.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsPluginContributionLeftOver<TClass, TValue>(
|
||||||
|
Expression<Func<Data, TClass>> configSelection,
|
||||||
|
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||||
|
IEnumerable<IAvailablePlugin> availablePlugins)
|
||||||
|
{
|
||||||
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!configMeta.HasPluginContribution || configMeta.PluginContributionByConfigPluginId == Guid.Empty)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.PluginContributionByConfigPluginId);
|
||||||
|
if (plugin is null)
|
||||||
|
{
|
||||||
|
configMeta.ClearPluginContribution();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,13 +387,13 @@ public static partial class ManagedConfiguration
|
|||||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (configMeta.MangedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
if (configMeta.LockedByConfigPluginId == Guid.Empty || !configMeta.IsLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.MangedByConfigPluginId);
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.LockedByConfigPluginId);
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
{
|
{
|
||||||
configMeta.ResetManagedState();
|
configMeta.ResetLockedConfiguration();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -121,8 +121,8 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
|||||||
// Config: preview features visibility
|
// Config: preview features visibility
|
||||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.PreviewVisibility, this.Id, settingsTable, dryRun);
|
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.PreviewVisibility, this.Id, settingsTable, dryRun);
|
||||||
|
|
||||||
// Config: enabled preview features
|
// Config: enabled preview features (plugin contribution; users can enable additional features)
|
||||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.EnabledPreviewFeatures, this.Id, settingsTable, dryRun);
|
ManagedConfiguration.TryProcessConfigurationWithPluginContribution(x => x.App, x => x.EnabledPreviewFeatures, this.Id, settingsTable, dryRun);
|
||||||
|
|
||||||
// Config: hide some assistants?
|
// Config: hide some assistants?
|
||||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.HiddenAssistants, this.Id, settingsTable, dryRun);
|
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.HiddenAssistants, this.Id, settingsTable, dryRun);
|
||||||
|
|||||||
@ -219,6 +219,9 @@ public static partial class PluginFactory
|
|||||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.EnabledPreviewFeatures, AVAILABLE_PLUGINS))
|
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.EnabledPreviewFeatures, AVAILABLE_PLUGINS))
|
||||||
wasConfigurationChanged = true;
|
wasConfigurationChanged = true;
|
||||||
|
|
||||||
|
if(ManagedConfiguration.IsPluginContributionLeftOver(x => x.App, x => x.EnabledPreviewFeatures, AVAILABLE_PLUGINS))
|
||||||
|
wasConfigurationChanged = true;
|
||||||
|
|
||||||
// Check for the transcription provider:
|
// Check for the transcription provider:
|
||||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UseTranscriptionProvider, AVAILABLE_PLUGINS))
|
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UseTranscriptionProvider, AVAILABLE_PLUGINS))
|
||||||
wasConfigurationChanged = true;
|
wasConfigurationChanged = true;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
- 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 single-input dialogs (e.g., renaming chats) so pressing `Enter` confirmed immediately and the input field focused automatically when the dialog opened.
|
- Improved single-input dialogs (e.g., renaming chats) so pressing `Enter` confirmed immediately and the input field focused automatically when the dialog opened.
|
||||||
- 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.
|
- 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.
|
||||||
|
- Improved the configuration plugins by making `EnabledPreviewFeatures` additive rather than exclusive. Users can now enable additional preview features without being restricted to those selected by the configuration plugin.
|
||||||
- Improved the system language detection for locale values such as `C` and variants like `de_DE.UTF-8`, enabling AI Studio to apply the matching UI language more reliably.
|
- Improved the system language detection for locale values such as `C` and variants like `de_DE.UTF-8`, enabling AI Studio to apply the matching UI language more reliably.
|
||||||
- Fixed an issue where leftover enterprise configuration plugins could remain active after organizational assignment changes during longer absences (for example, vacation), which could lead to configuration conflicts.
|
- Fixed an issue where leftover enterprise configuration plugins could remain active after organizational assignment changes during longer absences (for example, vacation), which could lead to configuration conflicts.
|
||||||
- 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.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user