diff --git a/app/MindWork AI Studio/Components/ReadWebContent.razor b/app/MindWork AI Studio/Components/ReadWebContent.razor
index 2a6aadb1..10ebc52d 100644
--- a/app/MindWork AI Studio/Components/ReadWebContent.razor
+++ b/app/MindWork AI Studio/Components/ReadWebContent.razor
@@ -5,8 +5,8 @@
{
-
-
+
+
@T("Fetch")
diff --git a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
index 550a8bde..22721a1d 100644
--- a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
+++ b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
@@ -35,7 +35,20 @@ public partial class ReadWebContent : MSGComponentBase
[Parameter]
public EventCallback ContentChanged { get; set; }
-
+
+ ///
+ /// The URL the content is loaded from.
+ ///
+ ///
+ /// The URL belongs to the parent, so that it is cleared when the parent resets its form and
+ /// is kept when the parent stores its state.
+ ///
+ [Parameter]
+ public string URL { get; set; } = string.Empty;
+
+ [Parameter]
+ public EventCallback URLChanged { get; set; }
+
[Parameter]
public AIStudio.Settings.Provider ProviderSettings { get; set; } = AIStudio.Settings.Provider.NONE;
@@ -60,8 +73,6 @@ public partial class ReadWebContent : MSGComponentBase
private readonly Process process = Process.INSTANCE;
private ProcessStepValue processStep;
- private string providedURL = string.Empty;
- private bool urlIsValid;
private bool isProviderValid;
private AIStudio.Settings.Provider providerSettings = AIStudio.Settings.Provider.NONE;
@@ -105,7 +116,7 @@ public partial class ReadWebContent : MSGComponentBase
// the URL, so their own network is not off limits.
//
var retrievedPage = await this.WebPageRetrievalService.RetrieveAsync(
- new Uri(this.providedURL),
+ new Uri(this.URL),
new WebPageRetrievalOptions
{
TimeoutSeconds = TIMEOUT_SECONDS,
@@ -115,14 +126,14 @@ public partial class ReadWebContent : MSGComponentBase
this.processStep = this.process[ReadWebContentSteps.PARSING];
this.StateHasChanged();
markdown = retrievedPage.ExtractedPage.Markdown;
- markdown = await this.PromptInjectionGuardService.SanitizeAsync(markdown, PromptInjectionSource.WebContent(this.providedURL));
+ markdown = await this.PromptInjectionGuardService.SanitizeAsync(markdown, PromptInjectionSource.WebContent(this.URL));
if (this.PreselectContentCleanerAgent && this.providerSettings != AIStudio.Settings.Provider.NONE)
{
this.AgentTextContentCleaner.ProviderSettings = this.providerSettings;
var additionalData = new Dictionary
{
- { "sourceURL", this.providedURL },
+ { "sourceURL", this.URL },
};
this.processStep = this.process[ReadWebContentSteps.CLEANING];
@@ -164,8 +175,8 @@ public partial class ReadWebContent : MSGComponentBase
// and the reasons a page cannot be read are things the user can act on: a link to a
// PDF rather than a page, a host that does not answer, a server refusing the request.
//
- this.Logger.LogWarning(exception, "Could not load the web content from '{ProvidedUrl}'.", this.providedURL);
- await this.MessageBus.SendError(new(Icons.Material.Filled.CloudOff, string.Format(this.T("The content of '{0}' could not be loaded: {1}"), this.providedURL, exception.Message)));
+ this.Logger.LogWarning(exception, "Could not load the web content from '{ProvidedUrl}'.", this.URL);
+ await this.MessageBus.SendError(new(Icons.Material.Filled.CloudOff, string.Format(this.T("The content of '{0}' could not be loaded: {1}"), this.URL, exception.Message)));
}
this.Content = markdown;
@@ -176,16 +187,31 @@ public partial class ReadWebContent : MSGComponentBase
{
get
{
- if(!this.urlIsValid)
+ if(!this.UrlIsValid)
return false;
-
+
if(this.PreselectContentCleanerAgent && !this.isProviderValid)
return false;
-
+
return true;
}
}
+ ///
+ /// Whether the current URL can be loaded.
+ ///
+ ///
+ /// Asked of the current value instead of remembered from the last validation run: the parent
+ /// clears the URL when it resets its form, and the form validation does not run again at that
+ /// point. The fetch button would otherwise stay enabled with an empty field.
+ ///
+ private bool UrlIsValid => this.ValidateURL(this.URL) is null;
+
+ private async Task URLValueChanged(string url)
+ {
+ await this.URLChanged.InvokeAsync(url);
+ }
+
private async Task ShowWebContentReaderChanged(bool state)
{
await this.PreselectChanged.InvokeAsync(state);
@@ -211,25 +237,15 @@ public partial class ReadWebContent : MSGComponentBase
private string? ValidateURL(string url)
{
if(string.IsNullOrWhiteSpace(url))
- {
- this.urlIsValid = false;
return T("Please provide a URL to load the content from.");
- }
var urlParsingResult = Uri.TryCreate(url, UriKind.Absolute, out var uriResult);
if(!urlParsingResult)
- {
- this.urlIsValid = false;
return T("Please provide a valid URL.");
- }
if(uriResult is not { Scheme: "http" or "https" })
- {
- this.urlIsValid = false;
return T("Please provide a valid HTTP or HTTPS URL.");
- }
- this.urlIsValid = true;
return null;
}
}
\ No newline at end of file