mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 13:00:20 +00:00 
			
		
		
		
	Basic implementation of the workspace component
This commit is contained in:
		
							parent
							
								
									b57d7d56ea
								
							
						
					
					
						commit
						12fdcc9d8f
					
				
							
								
								
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/ITreeItem.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/ITreeItem.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public interface ITreeItem<out T>;
 | 
			
		||||
							
								
								
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/TreeButton.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/TreeButton.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public readonly record struct TreeButton<T>(WorkspaceBranch Branch, int Depth, string Text, string Icon) : ITreeItem<T>;
 | 
			
		||||
							
								
								
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/TreeDivider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/MindWork AI Studio/Components/Blocks/TreeDivider.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public readonly record struct TreeDivider<T> : ITreeItem<T>;
 | 
			
		||||
							
								
								
									
										18
									
								
								app/MindWork AI Studio/Components/Blocks/TreeItemData.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/MindWork AI Studio/Components/Blocks/TreeItemData.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public class TreeItemData<T> : ITreeItem<T>
 | 
			
		||||
{
 | 
			
		||||
    public WorkspaceBranch Branch { get; init; } = WorkspaceBranch.NONE;
 | 
			
		||||
    
 | 
			
		||||
    public int Depth { get; init; }
 | 
			
		||||
    
 | 
			
		||||
    public string Text { get; init; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    public string Icon { get; init; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    public T? Value { get; init; }
 | 
			
		||||
 | 
			
		||||
    public bool Expandable { get; init; } = true;
 | 
			
		||||
 | 
			
		||||
    public HashSet<ITreeItem<T>> Children { get; } = [];
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public enum WorkspaceBranch
 | 
			
		||||
{
 | 
			
		||||
    NONE,
 | 
			
		||||
    
 | 
			
		||||
    WORKSPACES,
 | 
			
		||||
    TEMPORARY_CHATS,
 | 
			
		||||
}
 | 
			
		||||
@ -1 +1,41 @@
 | 
			
		||||
<MudText Typo="Typo.body1">TODO</MudText>
 | 
			
		||||
<MudTreeView T="ITreeItem<string>" ServerData="@this.LoadServerData" Items="@this.initialTreeItems" MultiSelection="@false" Hover="@true" ExpandOnClick="@true">
 | 
			
		||||
    <ItemTemplate Context="item">
 | 
			
		||||
        @switch (item)
 | 
			
		||||
        {
 | 
			
		||||
            case TreeDivider<string>:
 | 
			
		||||
                <li style="min-height: 1em;">
 | 
			
		||||
                    <MudDivider Style="margin-top: 1em; width: 90%; border-width: 3pt;"/>
 | 
			
		||||
                </li>
 | 
			
		||||
                break;
 | 
			
		||||
                
 | 
			
		||||
            case TreeItemData<string> treeItem:
 | 
			
		||||
                <MudTreeViewItem T="ITreeItem<string>" Icon="@treeItem.Icon" Value="@item" LoadingIconColor="@Color.Info" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
 | 
			
		||||
                    <BodyContent>
 | 
			
		||||
                        <div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
 | 
			
		||||
                            <MudText Style="justify-self: start;">@treeItem.Text</MudText>
 | 
			
		||||
                        
 | 
			
		||||
                            @if (treeItem.Value is not "root" and not "temp")
 | 
			
		||||
                            {
 | 
			
		||||
                                <div style="justify-self: end;">
 | 
			
		||||
                                    <MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Medium" Color="Color.Inherit"/>
 | 
			
		||||
                                    <MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Medium" Color="Color.Inherit"/>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            }
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </BodyContent>
 | 
			
		||||
                </MudTreeViewItem>
 | 
			
		||||
                break;
 | 
			
		||||
                
 | 
			
		||||
            case TreeButton<string> treeButton:
 | 
			
		||||
                <li>
 | 
			
		||||
                    <div class="mud-treeview-item-content" style="background-color: unset;">
 | 
			
		||||
                        <div class="mud-treeview-item-arrow"></div>
 | 
			
		||||
                        <MudButton StartIcon="@treeButton.Icon" Variant="Variant.Filled">
 | 
			
		||||
                            @treeButton.Text
 | 
			
		||||
                        </MudButton>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </li>
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    </ItemTemplate>
 | 
			
		||||
</MudTreeView>
 | 
			
		||||
@ -1,7 +1,161 @@
 | 
			
		||||
using Microsoft.AspNetCore.Components;
 | 
			
		||||
using AIStudio.Chat;
 | 
			
		||||
using AIStudio.Settings;
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Components;
 | 
			
		||||
 | 
			
		||||
namespace AIStudio.Components.Blocks;
 | 
			
		||||
 | 
			
		||||
public partial class Workspaces : ComponentBase
 | 
			
		||||
{
 | 
			
		||||
    [Inject]
 | 
			
		||||
    private SettingsManager SettingsManager { get; set; } = null!;
 | 
			
		||||
    
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public ChatThread? CurrentChatThread { get; set; }
 | 
			
		||||
 | 
			
		||||
    private readonly HashSet<ITreeItem<string>> initialTreeItems = new();
 | 
			
		||||
    
 | 
			
		||||
    #region Overrides of ComponentBase
 | 
			
		||||
 | 
			
		||||
    protected override async Task OnInitializedAsync()
 | 
			
		||||
    {
 | 
			
		||||
        //
 | 
			
		||||
        // Notice: In order to get the server-based loading to work, we need to respect the following rules:
 | 
			
		||||
        // - We must have initial tree items
 | 
			
		||||
        // - Those initial tree items cannot have children
 | 
			
		||||
        // - When assigning the tree items to the MudTreeViewItem component, we must set the Value property to the value of the item
 | 
			
		||||
        //
 | 
			
		||||
        
 | 
			
		||||
        this.initialTreeItems.Add(new TreeItemData<string>
 | 
			
		||||
        {
 | 
			
		||||
            Depth = 0,
 | 
			
		||||
            Branch = WorkspaceBranch.WORKSPACES,
 | 
			
		||||
            Text = "Workspaces",
 | 
			
		||||
            Icon = Icons.Material.Filled.Folder,
 | 
			
		||||
            Expandable = true,
 | 
			
		||||
            Value = "root",
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.initialTreeItems.Add(new TreeDivider<string>());
 | 
			
		||||
        this.initialTreeItems.Add(new TreeItemData<string>
 | 
			
		||||
        {
 | 
			
		||||
            Depth = 0,
 | 
			
		||||
            Branch = WorkspaceBranch.TEMPORARY_CHATS,
 | 
			
		||||
            Text = "Temporary chats",
 | 
			
		||||
            Icon = Icons.Material.Filled.Timer,
 | 
			
		||||
            Expandable = true,
 | 
			
		||||
            Value = "temp",
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        await base.OnInitializedAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    private Task<HashSet<ITreeItem<string>>> LoadServerData(ITreeItem<string>? parent)
 | 
			
		||||
    {
 | 
			
		||||
        switch (parent)
 | 
			
		||||
        {
 | 
			
		||||
            case TreeItemData<string> item:
 | 
			
		||||
                switch (item.Branch)
 | 
			
		||||
                {
 | 
			
		||||
                    case WorkspaceBranch.WORKSPACES:
 | 
			
		||||
                        var workspaceChildren = new HashSet<ITreeItem<string>>();
 | 
			
		||||
 | 
			
		||||
                        if (item.Depth == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            //
 | 
			
		||||
                            // Search for workspace folders in the data directory:
 | 
			
		||||
                            //
 | 
			
		||||
 | 
			
		||||
                            // Get the workspace root directory: 
 | 
			
		||||
                            var workspaceDirectories = Path.Join(SettingsManager.DataDirectory, "workspaces");
 | 
			
		||||
 | 
			
		||||
                            // Ensure the directory exists:
 | 
			
		||||
                            Directory.CreateDirectory(workspaceDirectories);
 | 
			
		||||
 | 
			
		||||
                            // Enumerate the workspace directories:
 | 
			
		||||
                            foreach (var workspaceDirPath in Directory.EnumerateDirectories(workspaceDirectories))
 | 
			
		||||
                            {
 | 
			
		||||
                                workspaceChildren.Add(new TreeItemData<string>
 | 
			
		||||
                                {
 | 
			
		||||
                                    Depth = item.Depth + 1,
 | 
			
		||||
                                    Branch = WorkspaceBranch.WORKSPACES,
 | 
			
		||||
                                    Text = Path.GetFileName(workspaceDirPath),
 | 
			
		||||
                                    Icon = Icons.Material.Filled.Description,
 | 
			
		||||
                                    Expandable = true,
 | 
			
		||||
                                    Value = workspaceDirPath,
 | 
			
		||||
                                });
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            workspaceChildren.Add(new TreeButton<string>(WorkspaceBranch.WORKSPACES, item.Depth + 1, "Add workspace",Icons.Material.Filled.Add));
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        else if (item.Depth == 1)
 | 
			
		||||
                        {
 | 
			
		||||
                            //
 | 
			
		||||
                            // Search for workspace chats in the workspace directory:
 | 
			
		||||
                            //
 | 
			
		||||
                            
 | 
			
		||||
                            // Get the workspace directory:
 | 
			
		||||
                            var workspaceDirPath = item.Value;
 | 
			
		||||
                            
 | 
			
		||||
                            if(workspaceDirPath is null)
 | 
			
		||||
                                return Task.FromResult(new HashSet<ITreeItem<string>>());
 | 
			
		||||
                            
 | 
			
		||||
                            // Enumerate the workspace directory:
 | 
			
		||||
                            foreach (var chatPath in Directory.EnumerateDirectories(workspaceDirPath))
 | 
			
		||||
                            {
 | 
			
		||||
                                workspaceChildren.Add(new TreeItemData<string>
 | 
			
		||||
                                {
 | 
			
		||||
                                    Depth = item.Depth + 1,
 | 
			
		||||
                                    Branch = WorkspaceBranch.WORKSPACES,
 | 
			
		||||
                                    Text = Path.GetFileNameWithoutExtension(chatPath),
 | 
			
		||||
                                    Icon = Icons.Material.Filled.Chat,
 | 
			
		||||
                                    Expandable = false,
 | 
			
		||||
                                    Value = chatPath,
 | 
			
		||||
                                });
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            workspaceChildren.Add(new TreeButton<string>(WorkspaceBranch.WORKSPACES, item.Depth + 1, "Add chat",Icons.Material.Filled.Add));
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return Task.FromResult(workspaceChildren);
 | 
			
		||||
                    
 | 
			
		||||
                    case WorkspaceBranch.TEMPORARY_CHATS:
 | 
			
		||||
                        var tempChildren = new HashSet<ITreeItem<string>>();
 | 
			
		||||
 | 
			
		||||
                        //
 | 
			
		||||
                        // Search for workspace folders in the data directory:
 | 
			
		||||
                        //
 | 
			
		||||
                        
 | 
			
		||||
                        // Get the workspace root directory: 
 | 
			
		||||
                        var temporaryDirectories = Path.Join(SettingsManager.DataDirectory, "tempChats");
 | 
			
		||||
                        
 | 
			
		||||
                        // Ensure the directory exists:
 | 
			
		||||
                        Directory.CreateDirectory(temporaryDirectories);
 | 
			
		||||
                        
 | 
			
		||||
                        // Enumerate the workspace directories:
 | 
			
		||||
                        foreach (var tempChatDirPath in Directory.EnumerateDirectories(temporaryDirectories))
 | 
			
		||||
                        {
 | 
			
		||||
                            tempChildren.Add(new TreeItemData<string>
 | 
			
		||||
                            {
 | 
			
		||||
                                Depth = item.Depth + 1,
 | 
			
		||||
                                Branch = WorkspaceBranch.TEMPORARY_CHATS,
 | 
			
		||||
                                Text = Path.GetFileName(tempChatDirPath),
 | 
			
		||||
                                Icon = Icons.Material.Filled.Timer,
 | 
			
		||||
                                Expandable = false,
 | 
			
		||||
                                Value = tempChatDirPath,
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        return Task.FromResult(tempChildren);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return Task.FromResult(new HashSet<ITreeItem<string>>());
 | 
			
		||||
            
 | 
			
		||||
            default:
 | 
			
		||||
                return Task.FromResult(new HashSet<ITreeItem<string>>());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user