mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 04:00:21 +00:00 
			
		
		
		
	Added possibility that the user selects a file
This commit is contained in:
		
							parent
							
								
									0c5417ad31
								
							
						
					
					
						commit
						cb744064d5
					
				
							
								
								
									
										17
									
								
								app/MindWork AI Studio/Components/SelectFile.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/MindWork AI Studio/Components/SelectFile.razor
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
<MudStack Row="@true" Spacing="3" Class="mb-3" StretchItems="StretchItems.None" AlignItems="AlignItems.Center">
 | 
			
		||||
    <MudTextField
 | 
			
		||||
        T="string"
 | 
			
		||||
        Text="@this.File"
 | 
			
		||||
        Label="@this.Label"
 | 
			
		||||
        ReadOnly="@true"
 | 
			
		||||
        Validation="@this.Validation"
 | 
			
		||||
        Adornment="Adornment.Start"
 | 
			
		||||
        AdornmentIcon="@Icons.Material.Filled.AttachFile"
 | 
			
		||||
        UserAttributes="@SPELLCHECK_ATTRIBUTES"
 | 
			
		||||
        Variant="Variant.Outlined"
 | 
			
		||||
    />
 | 
			
		||||
    
 | 
			
		||||
    <MudButton StartIcon="@Icons.Material.Filled.FolderOpen" Variant="Variant.Outlined" Color="Color.Primary" Disabled="this.Disabled" OnClick="@this.OpenFileDialog">
 | 
			
		||||
        Choose File
 | 
			
		||||
    </MudButton>
 | 
			
		||||
</MudStack>
 | 
			
		||||
							
								
								
									
										63
									
								
								app/MindWork AI Studio/Components/SelectFile.razor.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								app/MindWork AI Studio/Components/SelectFile.razor.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
using AIStudio.Settings;
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Components;
 | 
			
		||||
 | 
			
		||||
namespace AIStudio.Components;
 | 
			
		||||
 | 
			
		||||
public partial class SelectFile : ComponentBase
 | 
			
		||||
{
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public string File { get; set; } = string.Empty;
 | 
			
		||||
    
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public EventCallback<string> FileChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public bool Disabled { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public string Label { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public string FileDialogTitle { get; set; } = "Select File";
 | 
			
		||||
    
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<string, string?> Validation { get; set; } = _ => null;
 | 
			
		||||
    
 | 
			
		||||
    [Inject]
 | 
			
		||||
    private SettingsManager SettingsManager { get; init; } = null!;
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    public RustService RustService { get; set; } = null!;
 | 
			
		||||
    
 | 
			
		||||
    [Inject]
 | 
			
		||||
    protected ILogger<SelectDirectory> Logger { get; init; } = null!;
 | 
			
		||||
    
 | 
			
		||||
    private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
 | 
			
		||||
    
 | 
			
		||||
    #region Overrides of ComponentBase
 | 
			
		||||
 | 
			
		||||
    protected override async Task OnInitializedAsync()
 | 
			
		||||
    {
 | 
			
		||||
        // Configure the spellchecking for the instance name input:
 | 
			
		||||
        this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
 | 
			
		||||
        await base.OnInitializedAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    private void InternalFileChanged(string file)
 | 
			
		||||
    {
 | 
			
		||||
        this.File = file;
 | 
			
		||||
        this.FileChanged.InvokeAsync(file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task OpenFileDialog()
 | 
			
		||||
    {
 | 
			
		||||
        var response = await this.RustService.SelectFile(this.FileDialogTitle, string.IsNullOrWhiteSpace(this.File) ? null : this.File);
 | 
			
		||||
        this.Logger.LogInformation($"The user selected the file '{response.SelectedFilePath}'.");
 | 
			
		||||
 | 
			
		||||
        if (!response.UserCancelled)
 | 
			
		||||
            this.InternalFileChanged(response.SelectedFilePath);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
namespace AIStudio.Tools.Rust;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Data structure for selecting a file.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="UserCancelled">Was the file selection canceled?</param>
 | 
			
		||||
/// <param name="SelectedFilePath">The selected file, if any.</param>
 | 
			
		||||
public readonly record struct FileSelectionResponse(bool UserCancelled, string SelectedFilePath);
 | 
			
		||||
							
								
								
									
										7
									
								
								app/MindWork AI Studio/Tools/Rust/PreviousFile.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/MindWork AI Studio/Tools/Rust/PreviousFile.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
namespace AIStudio.Tools.Rust;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Data structure for selecting a file when a previous file was selected.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="FilePath">The path of the previous file.</param>
 | 
			
		||||
public readonly record struct PreviousFile(string FilePath);
 | 
			
		||||
@ -16,4 +16,17 @@ public sealed partial class RustService
 | 
			
		||||
        
 | 
			
		||||
        return await result.Content.ReadFromJsonAsync<DirectorySelectionResponse>(this.jsonRustSerializerOptions);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public async Task<FileSelectionResponse> SelectFile(string title, string? initialFile = null)
 | 
			
		||||
    {
 | 
			
		||||
        PreviousFile? previousFile = initialFile is null ? null : new (initialFile);
 | 
			
		||||
        var result = await this.http.PostAsJsonAsync($"/select/file?title={title}", previousFile, this.jsonRustSerializerOptions);
 | 
			
		||||
        if (!result.IsSuccessStatusCode)
 | 
			
		||||
        {
 | 
			
		||||
            this.logger!.LogError($"Failed to select a file: '{result.StatusCode}'");
 | 
			
		||||
            return new FileSelectionResponse(true, string.Empty);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return await result.Content.ReadFromJsonAsync<FileSelectionResponse>(this.jsonRustSerializerOptions);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -270,4 +270,53 @@ pub struct PreviousDirectory {
 | 
			
		||||
pub struct DirectorySelectionResponse {
 | 
			
		||||
    user_cancelled: bool,
 | 
			
		||||
    selected_directory: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Let the user select a file.
 | 
			
		||||
#[post("/select/file?<title>", data = "<previous_file>")]
 | 
			
		||||
pub fn select_file(_token: APIToken, title: &str, previous_file: Option<Json<PreviousFile>>) -> Json<FileSelectionResponse> {
 | 
			
		||||
    let file_path = match previous_file {
 | 
			
		||||
        Some(previous) => {
 | 
			
		||||
            let previous_path = previous.file_path.as_str();
 | 
			
		||||
            FileDialogBuilder::new()
 | 
			
		||||
                .set_title(title)
 | 
			
		||||
                .set_directory(previous_path)
 | 
			
		||||
                .pick_file()
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        None => {
 | 
			
		||||
            FileDialogBuilder::new()
 | 
			
		||||
                .set_title(title)
 | 
			
		||||
                .pick_file()
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    match file_path {
 | 
			
		||||
        Some(path) => {
 | 
			
		||||
            info!("User selected file: {path:?}");
 | 
			
		||||
            Json(FileSelectionResponse {
 | 
			
		||||
                user_cancelled: false,
 | 
			
		||||
                selected_file_path: path.to_str().unwrap().to_string(),
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        None => {
 | 
			
		||||
            info!("User cancelled file selection.");
 | 
			
		||||
            Json(FileSelectionResponse {
 | 
			
		||||
                user_cancelled: true,
 | 
			
		||||
                selected_file_path: String::from(""),
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Deserialize)]
 | 
			
		||||
pub struct PreviousFile {
 | 
			
		||||
    file_path: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct FileSelectionResponse {
 | 
			
		||||
    user_cancelled: bool,
 | 
			
		||||
    selected_file_path: String,
 | 
			
		||||
}
 | 
			
		||||
@ -85,6 +85,7 @@ pub fn start_runtime_api() {
 | 
			
		||||
                crate::app_window::check_for_update,
 | 
			
		||||
                crate::app_window::install_update,
 | 
			
		||||
                crate::app_window::select_directory,
 | 
			
		||||
                crate::app_window::select_file,
 | 
			
		||||
                crate::secret::get_secret,
 | 
			
		||||
                crate::secret::store_secret,
 | 
			
		||||
                crate::secret::delete_secret,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user