encapsulated render logic into a function to be able to call it recursively

This commit is contained in:
krut_ni 2026-03-10 16:45:01 +01:00
parent dbdcdef83c
commit 4f836e2dfb
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C
2 changed files with 239 additions and 247 deletions

View File

@ -1,4 +1,4 @@
@attribute [Route(Routes.ASSISTANT_DYNAMIC)] @attribute [Route(Routes.ASSISTANT_DYNAMIC)]
@using AIStudio.Components @using AIStudio.Components
@using AIStudio.Settings @using AIStudio.Settings
@using AIStudio.Tools.PluginSystem.Assistants.DataModel @using AIStudio.Tools.PluginSystem.Assistants.DataModel
@ -6,249 +6,242 @@
@foreach (var component in this.RootComponent!.Children) @foreach (var component in this.RootComponent!.Children)
{ {
@switch (component.Type) @this.RenderComponent(component)
{ }
case AssistantComponentType.TEXT_AREA:
if (component is AssistantTextArea textArea) @code {
{ private RenderFragment RenderChildren(IEnumerable<IAssistantComponent> children) => @<text>
var lines = textArea.IsSingleLine ? 1 : 6; @foreach (var child in children)
{
<MudTextField T="string" @this.RenderComponent(child)
@bind-Text="@this.inputFields[textArea.Name]" }
Label="@textArea.Label" </text>;
HelperText="@textArea.HelperText"
HelperTextOnFocus="@textArea.HelperTextOnFocus" private RenderFragment RenderComponent(IAssistantComponent component) => @<text>
ReadOnly="@textArea.ReadOnly" @switch (component.Type)
Counter="@textArea.Counter" {
MaxLength="@textArea.MaxLength" case AssistantComponentType.TEXT_AREA:
Immediate="@textArea.IsImmediate" if (component is AssistantTextArea textArea)
Adornment="@textArea.GetAdornmentPos()" {
AdornmentIcon="@textArea.GetIconSvg()" var lines = textArea.IsSingleLine ? 1 : 6;
AdornmentText="@textArea.AdornmentText"
AdornmentColor="@textArea.GetAdornmentColor()" <MudTextField T="string"
Variant="Variant.Outlined" @bind-Text="@this.inputFields[textArea.Name]"
Lines="@lines" Label="@textArea.Label"
AutoGrow="@true" HelperText="@textArea.HelperText"
MaxLines="12" HelperTextOnFocus="@textArea.HelperTextOnFocus"
Class='@MergeClass(textArea.Class, "mb-3")' ReadOnly="@textArea.ReadOnly"
Style="@this.GetOptionalStyle(textArea.Style)" Counter="@textArea.Counter"
/> MaxLength="@textArea.MaxLength"
} Immediate="@textArea.IsImmediate"
break; Adornment="@textArea.GetAdornmentPos()"
case AssistantComponentType.IMAGE: AdornmentIcon="@textArea.GetIconSvg()"
if (component is AssistantImage assistantImage) AdornmentText="@textArea.AdornmentText"
{ AdornmentColor="@textArea.GetAdornmentColor()"
var resolvedSource = this.ResolveImageSource(assistantImage); Variant="Variant.Outlined"
if (!string.IsNullOrWhiteSpace(resolvedSource)) Lines="@lines"
{ AutoGrow="@true"
var image = assistantImage; MaxLines="12"
<div Class="mb-4"> Class='@MergeClass(textArea.Class, "mb-3")'
<MudImage Fluid="true" Src="@resolvedSource" Alt="@image.Alt" Class='@MergeClass(image.Class, "rounded-lg mb-2")' Style="@this.GetOptionalStyle(image.Style)" Elevation="20"/> Style="@this.GetOptionalStyle(textArea.Style)" />
@if (!string.IsNullOrWhiteSpace(image.Caption)) }
{ break;
<MudText Typo="Typo.caption" Align="Align.Center">@image.Caption</MudText> case AssistantComponentType.IMAGE:
} if (component is AssistantImage assistantImage)
</div> {
} var resolvedSource = this.ResolveImageSource(assistantImage);
} if (!string.IsNullOrWhiteSpace(resolvedSource))
break; {
case AssistantComponentType.WEB_CONTENT_READER: var image = assistantImage;
if (component is AssistantWebContentReader webContent && this.webContentFields.TryGetValue(webContent.Name, out var webState)) <div Class="mb-4">
{ <MudImage Fluid="true" Src="@resolvedSource" Alt="@image.Alt" Class='@MergeClass(image.Class, "rounded-lg mb-2")' Style="@this.GetOptionalStyle(image.Style)" Elevation="20" />
<div class="@webContent.Class" style="@webContent.Style"> @if (!string.IsNullOrWhiteSpace(image.Caption))
<ReadWebContent @bind-Content="@webState.Content" {
ProviderSettings="@this.providerSettings" <MudText Typo="Typo.caption" Align="Align.Center">@image.Caption</MudText>
@bind-AgentIsRunning="@webState.AgentIsRunning" }
@bind-Preselect="@webState.Preselect" </div>
@bind-PreselectContentCleanerAgent="@webState.PreselectContentCleanerAgent"/> }
</div> }
} break;
break; case AssistantComponentType.WEB_CONTENT_READER:
case AssistantComponentType.FILE_CONTENT_READER: if (component is AssistantWebContentReader webContent && this.webContentFields.TryGetValue(webContent.Name, out var webState))
if (component is AssistantFileContentReader fileContent && this.fileContentFields.TryGetValue(fileContent.Name, out var fileState)) {
{ <div class="@webContent.Class" style="@webContent.Style">
<div class="@fileContent.Class" style="@fileContent.Style"> <ReadWebContent @bind-Content="@webState.Content"
<ReadFileContent @bind-FileContent="@fileState.Content" /> ProviderSettings="@this.providerSettings"
</div> @bind-AgentIsRunning="@webState.AgentIsRunning"
} @bind-Preselect="@webState.Preselect"
break; @bind-PreselectContentCleanerAgent="@webState.PreselectContentCleanerAgent" />
</div>
case AssistantComponentType.DROPDOWN: }
if (component is AssistantDropdown assistantDropdown) break;
{ case AssistantComponentType.FILE_CONTENT_READER:
<DynamicAssistantDropdown Items="@assistantDropdown.Items" if (component is AssistantFileContentReader fileContent && this.fileContentFields.TryGetValue(fileContent.Name, out var fileState))
@bind-Value="@this.dropdownFields[assistantDropdown.Name]" {
Default="@assistantDropdown.Default" <div class="@fileContent.Class" style="@fileContent.Style">
Label="@assistantDropdown.Label" <ReadFileContent @bind-FileContent="@fileState.Content" />
Icon="@Icons.Material.Filled.Translate" </div>
Class="@assistantDropdown.Class" }
Style="@assistantDropdown.Style"/> break;
} case AssistantComponentType.DROPDOWN:
break; if (component is AssistantDropdown assistantDropdown)
case AssistantComponentType.BUTTON: {
if (component is AssistantButton assistantButton) <DynamicAssistantDropdown Items="@assistantDropdown.Items"
{ @bind-Value="@this.dropdownFields[assistantDropdown.Name]"
var button = assistantButton; Default="@assistantDropdown.Default"
<div > Label="@assistantDropdown.Label"
<MudButton Variant="@button.GetButtonVariant()" Icon="@Icons.Material.Filled.Translate"
Color="@AssistantComponentPropHelper.GetColor(button.Color, Color.Default)" Class="@assistantDropdown.Class"
OnClick="@(() => this.ExecuteButtonActionAsync(button))" Style="@assistantDropdown.Style" />
Size="@AssistantComponentPropHelper.GetComponentSize(button.Size, Size.Medium)" }
FullWidth="@button.IsFullWidth" break;
StartIcon="@AssistantComponentPropHelper.GetIconSvg(button.StartIcon)" case AssistantComponentType.BUTTON:
EndIcon="@AssistantComponentPropHelper.GetIconSvg(button.EndIcon)" if (component is AssistantButton assistantButton)
IconColor="@AssistantComponentPropHelper.GetColor(button.IconColor, Color.Inherit)" {
IconSize="@AssistantComponentPropHelper.GetComponentSize(button.IconSize, Size.Medium)" var button = assistantButton;
Disabled="@this.IsButtonActionRunning(button.Name)" <div>
Class='@MergeClass(button.Class, "mb-3")' <MudButton Variant="@button.GetButtonVariant()"
Style="@this.GetOptionalStyle(button.Style)"> Color="@AssistantComponentPropHelper.GetColor(button.Color, Color.Default)"
@button.Text OnClick="@(() => this.ExecuteButtonActionAsync(button))"
</MudButton></div> Size="@AssistantComponentPropHelper.GetComponentSize(button.Size, Size.Medium)"
} FullWidth="@button.IsFullWidth"
break; StartIcon="@AssistantComponentPropHelper.GetIconSvg(button.StartIcon)"
case AssistantComponentType.BUTTON_GROUP: EndIcon="@AssistantComponentPropHelper.GetIconSvg(button.EndIcon)"
if (component is AssistantButtonGroup assistantButtonGroup) IconColor="@AssistantComponentPropHelper.GetColor(button.IconColor, Color.Inherit)"
{ IconSize="@AssistantComponentPropHelper.GetComponentSize(button.IconSize, Size.Medium)"
var buttonGroup = assistantButtonGroup; Disabled="@this.IsButtonActionRunning(button.Name)"
<MudButtonGroup Variant="@buttonGroup.GetVariant()" Class='@MergeClass(button.Class, "mb-3")'
Color="@AssistantComponentPropHelper.GetColor(buttonGroup.Color, Color.Default)" Style="@this.GetOptionalStyle(button.Style)">
Size="@AssistantComponentPropHelper.GetComponentSize(buttonGroup.Size, Size.Medium)" @button.Text
OverrideStyles="@buttonGroup.OverrideStyles" </MudButton>
Vertical="@buttonGroup.Vertical" </div>
DropShadow="@buttonGroup.DropShadow" }
Class='@MergeClass(buttonGroup.Class, "mb-3")' break;
Style="@this.GetOptionalStyle(buttonGroup.Style)"> case AssistantComponentType.BUTTON_GROUP:
@foreach (var child in buttonGroup.Children) if (component is AssistantButtonGroup assistantButtonGroup)
{ {
if (child is AssistantButton childButton) var buttonGroup = assistantButtonGroup;
{ <MudButtonGroup Variant="@buttonGroup.GetVariant()"
<MudButton Variant="@childButton.GetButtonVariant()" Color="@AssistantComponentPropHelper.GetColor(buttonGroup.Color, Color.Default)"
Color="@AssistantComponentPropHelper.GetColor(childButton.Color, Color.Default)" Size="@AssistantComponentPropHelper.GetComponentSize(buttonGroup.Size, Size.Medium)"
OnClick="@(() => this.ExecuteButtonActionAsync(childButton))" OverrideStyles="@buttonGroup.OverrideStyles"
Size="@AssistantComponentPropHelper.GetComponentSize(childButton.Size, Size.Medium)" Vertical="@buttonGroup.Vertical"
FullWidth="@childButton.IsFullWidth" DropShadow="@buttonGroup.DropShadow"
StartIcon="@AssistantComponentPropHelper.GetIconSvg(childButton.StartIcon)" Class='@MergeClass(buttonGroup.Class, "mb-3")'
EndIcon="@AssistantComponentPropHelper.GetIconSvg(childButton.EndIcon)" Style="@this.GetOptionalStyle(buttonGroup.Style)">
IconColor="@AssistantComponentPropHelper.GetColor(childButton.IconColor, Color.Inherit)" @this.RenderChildren(buttonGroup.Children)
IconSize="@AssistantComponentPropHelper.GetComponentSize(childButton.IconSize, Size.Medium)" </MudButtonGroup>
Disabled="@this.IsButtonActionRunning(childButton.Name)" }
Class="@childButton.Class" break;
Style="@this.GetOptionalStyle(childButton.Style)"> case AssistantComponentType.PROVIDER_SELECTION:
@childButton.Text if (component is AssistantProviderSelection providerSelection)
</MudButton> {
} <div class="@providerSelection.Class" style="@providerSelection.Style">
} <ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider" />
</MudButtonGroup> </div>
} }
break; break;
case AssistantComponentType.PROVIDER_SELECTION: case AssistantComponentType.PROFILE_SELECTION:
if (component is AssistantProviderSelection providerSelection) if (component is AssistantProfileSelection profileSelection)
{ {
<div class="@providerSelection.Class" style="@providerSelection.Style"> var selection = profileSelection;
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider" /> <div class="@selection.Class" style="@selection.Style">
</div> <ProfileFormSelection Validation="@((Profile profile) => this.ValidateProfileSelection(selection, profile))" @bind-Profile="@this.currentProfile" />
} </div>
break; }
case AssistantComponentType.PROFILE_SELECTION: break;
if (component is AssistantProfileSelection profileSelection) case AssistantComponentType.SWITCH:
{ if (component is AssistantSwitch switchComponent)
var selection = profileSelection; {
<div class="@selection.Class" style="@selection.Style"> var assistantSwitch = switchComponent;
<ProfileFormSelection Validation="@((Profile profile) => this.ValidateProfileSelection(selection, profile))" @bind-Profile="@this.currentProfile" /> var currentValue = this.switchFields[assistantSwitch.Name];
</div> <MudField Label="@assistantSwitch.Label" Variant="Variant.Outlined" Class="mb-3" Disabled="@assistantSwitch.Disabled">
} <MudSwitch T="bool"
break; Value="@currentValue"
case AssistantComponentType.SWITCH: ValueChanged="@((bool value) => this.switchFields[assistantSwitch.Name] = value)"
if (component is AssistantSwitch switchComponent) LabelPlacement="@assistantSwitch.GetLabelPlacement()"
{ Color="@assistantSwitch.GetColor(assistantSwitch.CheckedColor)"
var assistantSwitch = switchComponent; UncheckedColor="@assistantSwitch.GetColor(assistantSwitch.UncheckedColor)"
var currentValue = this.switchFields[assistantSwitch.Name]; ThumbIcon="@assistantSwitch.GetIconSvg()"
<MudField Label="@assistantSwitch.Label" Variant="Variant.Outlined" Class="mb-3" Disabled="@assistantSwitch.Disabled"> ThumbIconColor="@assistantSwitch.GetColor(assistantSwitch.IconColor)"
<MudSwitch T="bool" Disabled="@assistantSwitch.Disabled"
Value="@currentValue" Class="@assistantSwitch.Class"
ValueChanged="@((bool value) => this.switchFields[assistantSwitch.Name] = value)" Style="@this.GetOptionalStyle(assistantSwitch.Style)">
LabelPlacement="@assistantSwitch.GetLabelPlacement()" @(currentValue ? assistantSwitch.LabelOn : assistantSwitch.LabelOff)
Color="@assistantSwitch.GetColor(assistantSwitch.CheckedColor)" </MudSwitch>
UncheckedColor="@assistantSwitch.GetColor(assistantSwitch.UncheckedColor)" </MudField>
ThumbIcon="@assistantSwitch.GetIconSvg()" }
ThumbIconColor="@assistantSwitch.GetColor(assistantSwitch.IconColor)" break;
Disabled="@assistantSwitch.Disabled" case AssistantComponentType.HEADING:
Class="@assistantSwitch.Class" if (component is AssistantHeading assistantHeading)
Style="@this.GetOptionalStyle(assistantSwitch.Style)"> {
@(currentValue ? assistantSwitch.LabelOn : assistantSwitch.LabelOff) var heading = assistantHeading;
</MudSwitch> @switch (assistantHeading.Level)
</MudField> {
} case 1:
break; <MudText Typo="Typo.h4" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText>
case AssistantComponentType.HEADING: break;
if (component is AssistantHeading assistantHeading) case 2:
{ <MudText Typo="Typo.h5" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText>
var heading = assistantHeading; break;
@switch (assistantHeading.Level) case 3:
{ <MudText Typo="Typo.h6" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText>
case 1: break;
<MudText Typo="Typo.h4" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText> default:
break; <MudText Typo="Typo.h4" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText>
case 2: break;
<MudText Typo="Typo.h5" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText> }
break; }
case 3: break;
<MudText Typo="Typo.h6" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText> case AssistantComponentType.TEXT:
break; if (component is AssistantText assistantText)
default: {
<MudText Typo="Typo.h4" Class="@heading.Class" Style="@this.GetOptionalStyle(heading.Style)">@heading.Text</MudText> var text = assistantText;
break; <MudText Typo="Typo.body1" Class='@MergeClass(text.Class, "mb-3")' Style="@this.GetOptionalStyle(text.Style)">@text.Content</MudText>
} }
} break;
break; case AssistantComponentType.LIST:
case AssistantComponentType.TEXT: if (component is AssistantList assistantList)
if (component is AssistantText assistantText) {
{ var list = assistantList;
var text = assistantText; <MudList T="string" Class='@MergeClass(list.Class, "mb-6")' Style="@this.GetOptionalStyle(list.Style)">
<MudText Typo="Typo.body1" Class='@MergeClass(text.Class, "mb-3")' Style="@this.GetOptionalStyle(text.Style)">@text.Content</MudText> @foreach (var item in list.Items)
} {
break; @if (item.Type == "LINK")
case AssistantComponentType.LIST: {
if (component is AssistantList assistantList) <MudListItem T="string" Icon="@Icons.Material.Filled.Link" Target="_blank" Href="@item.Href">@item.Text</MudListItem>
{ }
var list = assistantList; else
<MudList T="string" Class='@MergeClass(list.Class, "mb-6")' Style="@this.GetOptionalStyle(list.Style)"> {
@foreach (var item in list.Items) <MudListItem T="string">@item.Text</MudListItem>
{ }
@if (item.Type == "LINK") }
{ </MudList>
<MudListItem T="string" Icon="@Icons.Material.Filled.Link" Target="_blank" Href="@item.Href">@item.Text</MudListItem> }
} break;
else case AssistantComponentType.COLOR_PICKER:
{ if (component is AssistantColorPicker assistantColorPicker)
<MudListItem T="string">@item.Text</MudListItem> {
} var colorPicker = assistantColorPicker;
} var variant = colorPicker.GetPickerVariant();
</MudList> var elevation = variant == PickerVariant.Static ? 6 : 0;
} var rounded = variant == PickerVariant.Static;
break;
case AssistantComponentType.COLOR_PICKER: <MudItem Class="d-flex">
if (component is AssistantColorPicker assistantColorPicker) <MudColorPicker @bind-Text="@this.colorPickerFields[colorPicker.Name]"
{ Label="@colorPicker.Label"
var colorPicker = assistantColorPicker; Placeholder="@colorPicker.Placeholder"
var variant = colorPicker.GetPickerVariant(); ShowAlpha="@colorPicker.ShowAlpha"
var elevation = variant == PickerVariant.Static ? 6 : 0; ShowToolbar="@colorPicker.ShowToolbar"
var rounded = variant == PickerVariant.Static; ShowModeSwitch="@colorPicker.ShowModeSwitch"
PickerVariant="@variant"
<MudItem Class="d-flex"> Rounded="@rounded"
<MudColorPicker @bind-Text="@this.colorPickerFields[colorPicker.Name]" Elevation="@elevation"
Label="@colorPicker.Label" Style="@($"color: {this.colorPickerFields[colorPicker.Name]};")"
Placeholder="@colorPicker.Placeholder" Class="@MergeClass(colorPicker.Class, "mb-3")" />
ShowAlpha="@colorPicker.ShowAlpha" </MudItem>
ShowToolbar="@colorPicker.ShowToolbar" }
ShowModeSwitch="@colorPicker.ShowModeSwitch" break;
PickerVariant="@variant" }
Rounded="@rounded" </text>;
Elevation="@elevation"
Style="@($"color: {this.colorPickerFields[colorPicker.Name]};")"
Class="@MergeClass(colorPicker.Class, "mb-3")"/>
</MudItem>
}
break;
}
} }

View File

@ -571,5 +571,4 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
var time = this.AddUserRequest(await this.CollectUserPromptAsync()); var time = this.AddUserRequest(await this.CollectUserPromptAsync());
await this.AddAIResponseAsync(time); await this.AddAIResponseAsync(time);
} }
} }