Skip to content

Commit d2ac4e2

Browse files
Added workspace display options (#184)
1 parent bd97c0f commit d2ac4e2

11 files changed

+183
-76
lines changed

app/MindWork AI Studio/Components/InnerScrolling.razor

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
@inherits MSGComponentBase
22

3-
<div class="d-flex flex-column" style="@this.Height">
3+
<div class="@this.Classes" style="@this.Styles">
4+
@if (this.HeaderContent is not null)
5+
{
6+
<div>
7+
@this.HeaderContent
8+
</div>
9+
}
410
<div class="flex-auto overflow-auto">
511
@this.ChildContent
612

app/MindWork AI Studio/Components/InnerScrolling.razor.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ namespace AIStudio.Components;
66

77
public partial class InnerScrolling : MSGComponentBase
88
{
9+
[Parameter]
10+
public bool FillEntireHorizontalSpace { get; set; }
11+
912
/// <summary>
1013
/// Set the height of anything above the scrolling content; usually a header.
1114
/// What we do is calc(100vh - HeaderHeight). Means, you can use multiple measures like
@@ -14,6 +17,9 @@ public partial class InnerScrolling : MSGComponentBase
1417
[Parameter]
1518
public string HeaderHeight { get; set; } = "3em";
1619

20+
[Parameter]
21+
public RenderFragment? HeaderContent { get; set; }
22+
1723
[Parameter]
1824
public RenderFragment? ChildContent { get; set; }
1925

@@ -22,6 +28,9 @@ public partial class InnerScrolling : MSGComponentBase
2228
/// </summary>
2329
[Parameter]
2430
public RenderFragment? FooterContent { get; set; }
31+
32+
[Parameter]
33+
public string Class { get; set; } = string.Empty;
2534

2635
[CascadingParameter]
2736
private MainLayout MainLayout { get; set; } = null!;
@@ -62,7 +71,9 @@ protected override async Task OnInitializedAsync()
6271

6372
#endregion
6473

65-
private string Height => $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight});";
74+
private string Styles => this.FillEntireHorizontalSpace ? $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight}); overflow-x: auto; min-width: 0;" : $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight}); flex-shrink: 0;";
75+
76+
private string Classes => this.FillEntireHorizontalSpace ? $"{this.Class} d-flex flex-column flex-grow-1" : $"{this.Class} d-flex flex-column";
6677

6778
public async Task ScrollToBottom()
6879
{

app/MindWork AI Studio/Components/Workspaces.razor

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<MudTreeView T="ITreeItem" Items="@this.treeItems" SelectionMode="SelectionMode.SingleSelection" Hover="@true" ExpandOnClick="@true">
1+
<MudTreeView T="ITreeItem" Items="@this.treeItems" SelectionMode="SelectionMode.SingleSelection" Hover="@true" ExpandOnClick="@true" Class="ma-3">
22
<ItemTemplate Context="item">
33
@switch (item.Value)
44
{
@@ -11,7 +11,7 @@
1111
case TreeItemData treeItem:
1212
@if (treeItem.Type is TreeItemType.CHAT)
1313
{
14-
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)">
14+
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)">
1515
<BodyContent>
1616
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
1717
<MudText Style="justify-self: start;">
@@ -44,7 +44,7 @@
4444
}
4545
else if (treeItem.Type is TreeItemType.WORKSPACE)
4646
{
47-
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
47+
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
4848
<BodyContent>
4949
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
5050
<MudText Style="justify-self: start;">@treeItem.Text</MudText>
@@ -63,7 +63,7 @@
6363
}
6464
else
6565
{
66-
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
66+
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
6767
<BodyContent>
6868
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
6969
<MudText Style="justify-self: start;">@treeItem.Text</MudText>

app/MindWork AI Studio/Components/Workspaces.razor.cs

+17-10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public partial class Workspaces : ComponentBase
3535
[Parameter]
3636
public Func<Task> LoadedChatWasChanged { get; set; } = () => Task.CompletedTask;
3737

38+
[Parameter]
39+
public bool ExpandRootNodes { get; set; } = true;
40+
3841
private const Placement WORKSPACE_ITEM_TOOLTIP_PLACEMENT = Placement.Bottom;
3942

4043
public static readonly Guid WORKSPACE_ID_BIAS = Guid.Parse("82050a4e-ee92-43d7-8ee5-ab512f847e02");
@@ -73,9 +76,9 @@ protected override async Task OnInitializedAsync()
7376

7477
private async Task LoadTreeItems()
7578
{
76-
this.treeItems.Clear();
77-
this.treeItems.Add(new TreeItemData<ITreeItem>
79+
var workspacesNode = new TreeItemData<ITreeItem>
7880
{
81+
Expanded = this.ExpandRootNodes,
7982
Expandable = true,
8083
Value = new TreeItemData
8184
{
@@ -87,16 +90,11 @@ private async Task LoadTreeItems()
8790
Path = "root",
8891
Children = await this.LoadWorkspaces(),
8992
},
90-
});
93+
};
9194

92-
this.treeItems.Add(new TreeItemData<ITreeItem>
93-
{
94-
Expandable = false,
95-
Value = new TreeDivider(),
96-
});
97-
98-
this.treeItems.Add(new TreeItemData<ITreeItem>
95+
var tempChatNode = new TreeItemData<ITreeItem>
9996
{
97+
Expanded = this.ExpandRootNodes,
10098
Expandable = true,
10199
Value = new TreeItemData
102100
{
@@ -108,7 +106,16 @@ private async Task LoadTreeItems()
108106
Path = "temp",
109107
Children = await this.LoadTemporaryChats(),
110108
},
109+
};
110+
111+
this.treeItems.Clear();
112+
this.treeItems.Add(workspacesNode);
113+
this.treeItems.Add(new TreeItemData<ITreeItem>
114+
{
115+
Expandable = false,
116+
Value = new TreeDivider(),
111117
});
118+
this.treeItems.Add(tempChatNode);
112119
}
113120

114121
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadTemporaryChats()

app/MindWork AI Studio/Pages/Chat.razor

+99-56
Original file line numberDiff line numberDiff line change
@@ -16,82 +16,125 @@
1616
</MudText>
1717

1818
<ProviderSelection @bind-ProviderSettings="@this.providerSettings"/>
19-
<InnerScrolling @ref="@this.scrollingArea" HeaderHeight="12.3em">
20-
<ChildContent>
21-
@if (this.chatThread is not null)
19+
<MudStack Row="@true" Style="width: 100%; overflow: hidden;">
20+
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES
21+
&& this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR
22+
&& !this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible)
23+
{
24+
<MudPaper Class="border border-solid rounded-lg">
25+
<MudTooltip Text="Show your workspaces" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
26+
<MudIconButton Size="Size.Large" Icon="@this.WorkspaceSidebarToggleIcon" OnClick="() => this.ToggleWorkspaceSidebar()"/>
27+
</MudTooltip>
28+
</MudPaper>
29+
}
30+
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
31+
{
32+
@if ((this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR && this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible) || this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.SIDEBAR_ALWAYS_VISIBLE)
2233
{
23-
foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time))
34+
@if (this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR && this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible)
2435
{
25-
@if (!block.HideFromUser)
26-
{
27-
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content"/>
28-
}
36+
<InnerScrolling HeaderHeight="12.3em" Class="border border-solid rounded-lg">
37+
<HeaderContent>
38+
<MudTooltip Text="Hide your workspaces" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
39+
<MudIconButton Size="Size.Large" Icon="@this.WorkspaceSidebarToggleIcon" OnClick="() => this.ToggleWorkspaceSidebar()"/>
40+
</MudTooltip>
41+
</HeaderContent>
42+
<ChildContent>
43+
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" LoadedChatWasChanged="this.LoadedChatChanged"/>
44+
</ChildContent>
45+
</InnerScrolling>
2946
}
30-
}
31-
</ChildContent>
32-
<FooterContent>
33-
<MudElement Style="flex: 0 0 auto;">
34-
<MudTextField T="string" @ref="@this.inputField" @bind-Text="@this.userInput" Variant="Variant.Outlined" AutoGrow="@true" Lines="3" MaxLines="12" Label="@this.InputLabel" Placeholder="@this.ProviderPlaceholder" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Send" OnAdornmentClick="() => this.SendMessage()" ReadOnly="!this.IsProviderSelected || this.isStreaming" Immediate="@true" OnKeyUp="this.InputKeyEvent" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="@this.UserInputClass" Style="@this.UserInputStyle"/>
35-
</MudElement>
36-
<MudToolBar WrapContent="true" Gutters="@false" Class="border border-solid rounded" Style="border-color: lightgrey;">
37-
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
47+
else
3848
{
39-
<MudTooltip Text="Your workspaces" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
40-
<MudIconButton Icon="@Icons.Material.Filled.SnippetFolder" OnClick="() => this.ToggleWorkspaces()"/>
41-
</MudTooltip>
49+
<InnerScrolling HeaderHeight="12.3em" Class="border border-solid rounded-lg">
50+
<ChildContent>
51+
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" LoadedChatWasChanged="this.LoadedChatChanged"/>
52+
</ChildContent>
53+
</InnerScrolling>
4254
}
43-
44-
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY)
55+
}
56+
}
57+
<InnerScrolling FillEntireHorizontalSpace="@true" @ref="@this.scrollingArea" HeaderHeight="12.3em">
58+
<ChildContent>
59+
@if (this.chatThread is not null)
4560
{
46-
<MudTooltip Text="Save chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
47-
<MudIconButton Icon="@Icons.Material.Filled.Save" OnClick="() => this.SaveThread()" Disabled="@(!this.CanThreadBeSaved)"/>
48-
</MudTooltip>
61+
foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time))
62+
{
63+
@if (!block.HideFromUser)
64+
{
65+
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content"/>
66+
}
67+
}
4968
}
69+
</ChildContent>
70+
<FooterContent>
71+
<MudElement Style="flex: 0 0 auto;">
72+
<MudTextField T="string" @ref="@this.inputField" @bind-Text="@this.userInput" Variant="Variant.Outlined" AutoGrow="@true" Lines="3" MaxLines="12" Label="@this.InputLabel" Placeholder="@this.ProviderPlaceholder" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Send" OnAdornmentClick="() => this.SendMessage()" ReadOnly="!this.IsProviderSelected || this.isStreaming" Immediate="@true" OnKeyUp="this.InputKeyEvent" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="@this.UserInputClass" Style="@this.UserInputStyle"/>
73+
</MudElement>
74+
<MudToolBar WrapContent="true" Gutters="@false" Class="border border-solid rounded" Style="border-color: lightgrey;">
75+
@if (
76+
this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES
77+
&& this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY)
78+
{
79+
<MudTooltip Text="Show your workspaces" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
80+
<MudIconButton Icon="@Icons.Material.Filled.SnippetFolder" OnClick="() => this.ToggleWorkspaceOverlay()"/>
81+
</MudTooltip>
82+
}
5083

51-
<MudTooltip Text="Start temporary chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
52-
<MudIconButton Icon="@Icons.Material.Filled.AddComment" OnClick="() => this.StartNewChat(useSameWorkspace: false)"/>
53-
</MudTooltip>
84+
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY)
85+
{
86+
<MudTooltip Text="Save chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
87+
<MudIconButton Icon="@Icons.Material.Filled.Save" OnClick="() => this.SaveThread()" Disabled="@(!this.CanThreadBeSaved)"/>
88+
</MudTooltip>
89+
}
5490

55-
@if (!string.IsNullOrWhiteSpace(this.currentWorkspaceName))
56-
{
57-
<MudTooltip Text="@this.TooltipAddChatToWorkspace" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
58-
<MudIconButton Icon="@Icons.Material.Filled.CommentBank" OnClick="() => this.StartNewChat(useSameWorkspace: true)"/>
91+
<MudTooltip Text="Start temporary chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
92+
<MudIconButton Icon="@Icons.Material.Filled.AddComment" OnClick="() => this.StartNewChat(useSameWorkspace: false)"/>
5993
</MudTooltip>
60-
}
61-
62-
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
63-
{
64-
<MudTooltip Text="Delete this chat & start a new one" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
65-
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="() => this.StartNewChat(useSameWorkspace: true, deletePreviousChat: true)" Disabled="@(!this.CanThreadBeSaved)"/>
66-
</MudTooltip>
67-
}
6894

69-
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
70-
{
71-
<MudTooltip Text="Move the chat to a workspace, or to another if it is already in one." Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
72-
<MudIconButton Icon="@Icons.Material.Filled.MoveToInbox" Disabled="@(!this.CanThreadBeSaved)" OnClick="() => this.MoveChatToWorkspace()"/>
73-
</MudTooltip>
74-
}
95+
@if (!string.IsNullOrWhiteSpace(this.currentWorkspaceName))
96+
{
97+
<MudTooltip Text="@this.TooltipAddChatToWorkspace" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
98+
<MudIconButton Icon="@Icons.Material.Filled.CommentBank" OnClick="() => this.StartNewChat(useSameWorkspace: true)"/>
99+
</MudTooltip>
100+
}
75101

76-
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
77-
{
78-
<ConfidenceInfo Mode="ConfidenceInfoMode.ICON" LLMProvider="@this.providerSettings.UsedLLMProvider"/>
79-
}
102+
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
103+
{
104+
<MudTooltip Text="Delete this chat & start a new one" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
105+
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="() => this.StartNewChat(useSameWorkspace: true, deletePreviousChat: true)" Disabled="@(!this.CanThreadBeSaved)"/>
106+
</MudTooltip>
107+
}
108+
109+
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
110+
{
111+
<MudTooltip Text="Move the chat to a workspace, or to another if it is already in one." Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
112+
<MudIconButton Icon="@Icons.Material.Filled.MoveToInbox" Disabled="@(!this.CanThreadBeSaved)" OnClick="() => this.MoveChatToWorkspace()"/>
113+
</MudTooltip>
114+
}
115+
116+
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
117+
{
118+
<ConfidenceInfo Mode="ConfidenceInfoMode.ICON" LLMProvider="@this.providerSettings.UsedLLMProvider"/>
119+
}
80120

81-
<ProfileSelection CurrentProfile="@this.currentProfile" CurrentProfileChanged="@this.ProfileWasChanged" />
82-
</MudToolBar>
83-
</FooterContent>
84-
</InnerScrolling>
121+
<ProfileSelection CurrentProfile="@this.currentProfile" CurrentProfileChanged="@this.ProfileWasChanged" />
122+
</MudToolBar>
123+
</FooterContent>
124+
</InnerScrolling>
125+
</MudStack>
85126

86-
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior != WorkspaceStorageBehavior.DISABLE_WORKSPACES)
127+
@if (
128+
this.SettingsManager.ConfigurationData.Workspace.StorageBehavior != WorkspaceStorageBehavior.DISABLE_WORKSPACES
129+
&& this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY)
87130
{
88-
<MudDrawer @bind-Open="@this.workspacesVisible" Width="40em" Height="100%" Anchor="Anchor.Start" Variant="DrawerVariant.Temporary" Elevation="1">
131+
<MudDrawer @bind-Open="@this.workspaceOverlayVisible" Width="40em" Height="100%" Anchor="Anchor.Start" Variant="DrawerVariant.Temporary" Elevation="1">
89132
<MudDrawerHeader>
90133
<MudStack Row="@true" AlignItems="AlignItems.Center">
91134
<MudText Typo="Typo.h6" Class="mr-3">
92135
Your workspaces
93136
</MudText>
94-
<MudIconButton Icon="@Icons.Material.Filled.Close" Variant="Variant.Filled" Color="Color.Default" Size="Size.Small" OnClick="() => this.ToggleWorkspaces()"/>
137+
<MudIconButton Icon="@Icons.Material.Filled.Close" Variant="Variant.Filled" Color="Color.Default" Size="Size.Small" OnClick="() => this.ToggleWorkspaceOverlay()"/>
95138
</MudStack>
96139
</MudDrawerHeader>
97140
<MudDrawerContainer Class="ml-6">

0 commit comments

Comments
 (0)