mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-05-21 12:12:14 +00:00
Introduced additive configuration handling for managed preview features (e.g., merging user-defined and plugin-defined settings).
This commit is contained in:
parent
ea4e3f0199
commit
0d42a748bf
@ -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?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.IsLocked"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,30 @@ 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.GetManagedPreviewFeatures());
|
||||||
|
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<PreviewFeatures> GetManagedPreviewFeatures()
|
||||||
|
{
|
||||||
|
if (ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.HasManagedValue)
|
||||||
|
return meta.ManagedValue.Where(x => !x.IsReleased()).ToHashSet();
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<PreviewFeatures> GetSelectedPreviewFeatures()
|
||||||
|
{
|
||||||
|
var enabled = this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures.Where(x => !x.IsReleased()).ToHashSet();
|
||||||
|
enabled.UnionWith(this.GetManagedPreviewFeatures());
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEnabledPreviewFeatures(HashSet<PreviewFeatures> selectedFeatures)
|
||||||
|
{
|
||||||
|
selectedFeatures.UnionWith(this.GetManagedPreviewFeatures());
|
||||||
|
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = selectedFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
||||||
|
|||||||
@ -42,6 +42,21 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public required TValue Default { get; init; }
|
public required TValue Default { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether a managed value is available.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasManagedValue { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The managed value provided by a configuration plugin.
|
||||||
|
/// </summary>
|
||||||
|
public TValue ManagedValue { get; private set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the plugin that provided the managed value.
|
||||||
|
/// </summary>
|
||||||
|
public Guid ManagedValueByConfigPluginId { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the configuration state, indicating that it is managed by a specific plugin.
|
/// Locks the configuration state, indicating that it is managed by a specific plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -63,6 +78,35 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
|||||||
this.Reset();
|
this.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unlocks the configuration state without changing the current value.
|
||||||
|
/// </summary>
|
||||||
|
public void UnlockManagedState()
|
||||||
|
{
|
||||||
|
this.IsLocked = false;
|
||||||
|
this.MangedByConfigPluginId = Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores a managed value provided by a configuration plugin.
|
||||||
|
/// </summary>
|
||||||
|
public void SetManagedValue(TValue value, Guid pluginId)
|
||||||
|
{
|
||||||
|
this.ManagedValue = value;
|
||||||
|
this.ManagedValueByConfigPluginId = pluginId;
|
||||||
|
this.HasManagedValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the managed value without changing the current value.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearManagedValue()
|
||||||
|
{
|
||||||
|
this.ManagedValue = default!;
|
||||||
|
this.ManagedValueByConfigPluginId = Guid.Empty;
|
||||||
|
this.HasManagedValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the configuration property to its default value.
|
/// Resets the configuration property to its default value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -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 the configuration settings from a Lua table for enum set types.
|
||||||
|
/// The configured values are merged into the existing set and the setting is left 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 TryProcessConfigurationAdditive<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.SetManagedValue(new HashSet<TValue>(configuredValue), configPluginId);
|
||||||
|
}
|
||||||
|
else if (configMeta.HasManagedValue && configMeta.ManagedValueByConfigPluginId == configPluginId)
|
||||||
|
{
|
||||||
|
configMeta.ClearManagedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configMeta.IsLocked && configMeta.MangedByConfigPluginId == configPluginId)
|
||||||
|
configMeta.UnlockManagedState();
|
||||||
|
|
||||||
|
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>
|
||||||
|
|||||||
@ -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
|
||||||
@ -353,6 +354,31 @@ public static partial class ManagedConfiguration
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a managed value is left over from a configuration plugin that is no longer available.
|
||||||
|
/// If so, it clears the managed value and returns true.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsManagedValueLeftOver<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.HasManagedValue || configMeta.ManagedValueByConfigPluginId == Guid.Empty)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var plugin = availablePlugins.FirstOrDefault(x => x.Id == configMeta.ManagedValueByConfigPluginId);
|
||||||
|
if (plugin is null)
|
||||||
|
{
|
||||||
|
configMeta.ClearManagedValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsConfigurationLeftOver<TClass>(
|
public static bool IsConfigurationLeftOver<TClass>(
|
||||||
Expression<Func<Data, TClass>> configSelection,
|
Expression<Func<Data, TClass>> configSelection,
|
||||||
Expression<Func<TClass, IDictionary<string, string>>> propertyExpression,
|
Expression<Func<TClass, IDictionary<string, string>>> propertyExpression,
|
||||||
|
|||||||
@ -108,8 +108,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 (additive; users can enable additional features)
|
||||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.EnabledPreviewFeatures, this.Id, settingsTable, dryRun);
|
ManagedConfiguration.TryProcessConfigurationAdditive(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);
|
||||||
|
|||||||
@ -180,6 +180,8 @@ public static partial class PluginFactory
|
|||||||
// Check for enabled preview features:
|
// Check for enabled preview features:
|
||||||
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.IsManagedValueLeftOver(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))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user