diff --git a/app/MindWork AI Studio/Components/InnerScrolling.razor b/app/MindWork AI Studio/Components/InnerScrolling.razor index 83fd15e..5a2da66 100644 --- a/app/MindWork AI Studio/Components/InnerScrolling.razor +++ b/app/MindWork AI Studio/Components/InnerScrolling.razor @@ -1,6 +1,12 @@ @inherits MSGComponentBase -
+
+ @if (this.HeaderContent is not null) + { +
+ @this.HeaderContent +
+ }
@this.ChildContent diff --git a/app/MindWork AI Studio/Components/InnerScrolling.razor.cs b/app/MindWork AI Studio/Components/InnerScrolling.razor.cs index 0ac5846..1bce390 100644 --- a/app/MindWork AI Studio/Components/InnerScrolling.razor.cs +++ b/app/MindWork AI Studio/Components/InnerScrolling.razor.cs @@ -6,6 +6,9 @@ namespace AIStudio.Components; public partial class InnerScrolling : MSGComponentBase { + [Parameter] + public bool FillEntireHorizontalSpace { get; set; } + /// /// Set the height of anything above the scrolling content; usually a header. /// What we do is calc(100vh - HeaderHeight). Means, you can use multiple measures like @@ -14,6 +17,9 @@ public partial class InnerScrolling : MSGComponentBase [Parameter] public string HeaderHeight { get; set; } = "3em"; + [Parameter] + public RenderFragment? HeaderContent { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } @@ -22,6 +28,9 @@ public partial class InnerScrolling : MSGComponentBase /// [Parameter] public RenderFragment? FooterContent { get; set; } + + [Parameter] + public string Class { get; set; } = string.Empty; [CascadingParameter] private MainLayout MainLayout { get; set; } = null!; @@ -62,7 +71,9 @@ public partial class InnerScrolling : MSGComponentBase #endregion - private string Height => $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight});"; + 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;"; + + private string Classes => this.FillEntireHorizontalSpace ? $"{this.Class} d-flex flex-column flex-grow-1" : $"{this.Class} d-flex flex-column"; public async Task ScrollToBottom() { diff --git a/app/MindWork AI Studio/Components/Workspaces.razor b/app/MindWork AI Studio/Components/Workspaces.razor index da8f503..3046577 100644 --- a/app/MindWork AI Studio/Components/Workspaces.razor +++ b/app/MindWork AI Studio/Components/Workspaces.razor @@ -1,4 +1,4 @@ - + @switch (item.Value) { @@ -11,7 +11,7 @@ case TreeItemData treeItem: @if (treeItem.Type is TreeItemType.CHAT) { - +
@@ -44,7 +44,7 @@ } else if (treeItem.Type is TreeItemType.WORKSPACE) { - +
@treeItem.Text @@ -63,7 +63,7 @@ } else { - +
@treeItem.Text diff --git a/app/MindWork AI Studio/Components/Workspaces.razor.cs b/app/MindWork AI Studio/Components/Workspaces.razor.cs index fcb845e..48d77e2 100644 --- a/app/MindWork AI Studio/Components/Workspaces.razor.cs +++ b/app/MindWork AI Studio/Components/Workspaces.razor.cs @@ -35,6 +35,9 @@ public partial class Workspaces : ComponentBase [Parameter] public Func LoadedChatWasChanged { get; set; } = () => Task.CompletedTask; + [Parameter] + public bool ExpandRootNodes { get; set; } = true; + private const Placement WORKSPACE_ITEM_TOOLTIP_PLACEMENT = Placement.Bottom; public static readonly Guid WORKSPACE_ID_BIAS = Guid.Parse("82050a4e-ee92-43d7-8ee5-ab512f847e02"); @@ -73,9 +76,9 @@ public partial class Workspaces : ComponentBase private async Task LoadTreeItems() { - this.treeItems.Clear(); - this.treeItems.Add(new TreeItemData + var workspacesNode = new TreeItemData { + Expanded = this.ExpandRootNodes, Expandable = true, Value = new TreeItemData { @@ -87,16 +90,11 @@ public partial class Workspaces : ComponentBase Path = "root", Children = await this.LoadWorkspaces(), }, - }); + }; - this.treeItems.Add(new TreeItemData - { - Expandable = false, - Value = new TreeDivider(), - }); - - this.treeItems.Add(new TreeItemData + var tempChatNode = new TreeItemData { + Expanded = this.ExpandRootNodes, Expandable = true, Value = new TreeItemData { @@ -108,7 +106,16 @@ public partial class Workspaces : ComponentBase Path = "temp", Children = await this.LoadTemporaryChats(), }, + }; + + this.treeItems.Clear(); + this.treeItems.Add(workspacesNode); + this.treeItems.Add(new TreeItemData + { + Expandable = false, + Value = new TreeDivider(), }); + this.treeItems.Add(tempChatNode); } private async Task>> LoadTemporaryChats() diff --git a/app/MindWork AI Studio/Pages/Chat.razor b/app/MindWork AI Studio/Pages/Chat.razor index 8162231..5a386cc 100644 --- a/app/MindWork AI Studio/Pages/Chat.razor +++ b/app/MindWork AI Studio/Pages/Chat.razor @@ -16,82 +16,125 @@ - - - @if (this.chatThread is not null) + + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES + && this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR + && !this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible) + { + + + + + + } + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES) + { + @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) { - foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time)) + @if (this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR && this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible) { - @if (!block.HideFromUser) - { - - } + + + + + + + + + + + } + else + { + + + + + } } - - - - - - - @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES) + } + + + @if (this.chatThread is not null) { - - + foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time)) + { + @if (!block.HideFromUser) + { + + } + } + } + + + + + + + @if ( + this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES + && this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY) + { + + + + } + + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY) + { + + + + } + + + - } - @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY) - { - - - - } + @if (!string.IsNullOrWhiteSpace(this.currentWorkspaceName)) + { + + + + } - - - + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY) + { + + + + } - @if (!string.IsNullOrWhiteSpace(this.currentWorkspaceName)) - { - - - - } - - @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY) - { - - - - } + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES) + { + + + + } - @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES) - { - - - - } + @if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence) + { + + } - @if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence) - { - - } + + + + + - - - - - -@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior != WorkspaceStorageBehavior.DISABLE_WORKSPACES) +@if ( + this.SettingsManager.ConfigurationData.Workspace.StorageBehavior != WorkspaceStorageBehavior.DISABLE_WORKSPACES + && this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY) { - + Your workspaces - + diff --git a/app/MindWork AI Studio/Pages/Chat.razor.cs b/app/MindWork AI Studio/Pages/Chat.razor.cs index 909b3cb..6452dc9 100644 --- a/app/MindWork AI Studio/Pages/Chat.razor.cs +++ b/app/MindWork AI Studio/Pages/Chat.razor.cs @@ -42,7 +42,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable private string userInput = string.Empty; private string currentWorkspaceName = string.Empty; private Guid currentWorkspaceId = Guid.Empty; - private bool workspacesVisible; + private bool workspaceOverlayVisible; private Workspaces? workspaces; private bool mustScrollToBottomAfterRender; private bool mustStoreChat; @@ -157,6 +157,8 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable private string UserInputStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager) : string.Empty; private string UserInputClass => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? "confidence-border" : string.Empty; + + private string WorkspaceSidebarToggleIcon => this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible ? Icons.Material.Filled.ArrowCircleLeft : Icons.Material.Filled.ArrowCircleRight; private void ProfileWasChanged(Profile profile) { @@ -308,9 +310,15 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable } } - private void ToggleWorkspaces() + private void ToggleWorkspaceOverlay() { - this.workspacesVisible = !this.workspacesVisible; + this.workspaceOverlayVisible = !this.workspaceOverlayVisible; + } + + private async Task ToggleWorkspaceSidebar() + { + this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible = !this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible; + await this.SettingsManager.StoreSettings(); } private async Task SaveThread() diff --git a/app/MindWork AI Studio/Pages/Settings.razor b/app/MindWork AI Studio/Pages/Settings.razor index f37b277..9ccbfe0 100644 --- a/app/MindWork AI Studio/Pages/Settings.razor +++ b/app/MindWork AI Studio/Pages/Settings.razor @@ -202,7 +202,12 @@ - + + @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES) + { + + + } diff --git a/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs b/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs index 517a8a1..7a65fb8 100644 --- a/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs +++ b/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs @@ -58,6 +58,13 @@ public static class ConfigurationSelectDataFactory yield return new("Delete temporary chats older than 1 year", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_365_DAYS); } + public static IEnumerable> GetWorkspaceDisplayBehaviorData() + { + yield return new("Toggle the overlay: the chat uses all the space, workspaces are temporarily shown", WorkspaceDisplayBehavior.TOGGLE_OVERLAY); + yield return new("Toggle the sidebar: show the workspaces next to the chat when desired", WorkspaceDisplayBehavior.TOGGLE_SIDEBAR); + yield return new("Sidebar is always visible: show the workspaces next to the chat all the time", WorkspaceDisplayBehavior.SIDEBAR_ALWAYS_VISIBLE); + } + public static IEnumerable> GetNavBehaviorData() { yield return new("Navigation expands on mouse hover", NavBehavior.EXPAND_ON_HOVER); diff --git a/app/MindWork AI Studio/Settings/DataModel/DataWorkspace.cs b/app/MindWork AI Studio/Settings/DataModel/DataWorkspace.cs index 5041fc1..2fee8cb 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataWorkspace.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataWorkspace.cs @@ -11,4 +11,14 @@ public sealed class DataWorkspace /// The chat storage maintenance behavior. /// public WorkspaceStorageTemporaryMaintenancePolicy StorageTemporaryMaintenancePolicy { get; set; } = WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_90_DAYS; + + /// + /// The behavior used for displaying the workspace. + /// + public WorkspaceDisplayBehavior DisplayBehavior { get; set; } = WorkspaceDisplayBehavior.TOGGLE_SIDEBAR; + + /// + /// Indicates whether the sidebar is currently visible. + /// + public bool IsSidebarVisible { get; set; } = true; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/WorkspaceDisplayBehavior.cs b/app/MindWork AI Studio/Settings/DataModel/WorkspaceDisplayBehavior.cs new file mode 100644 index 0000000..8deccf1 --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/WorkspaceDisplayBehavior.cs @@ -0,0 +1,9 @@ +namespace AIStudio.Settings.DataModel; + +public enum WorkspaceDisplayBehavior +{ + TOGGLE_OVERLAY, + + TOGGLE_SIDEBAR, + SIDEBAR_ALWAYS_VISIBLE, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.16.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.16.md index f3e8b42..253a09f 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.16.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.16.md @@ -1,4 +1,5 @@ # v0.9.16, build 191 (2024-11-xx xx:xx UTC) - Added our second financial contributor: Thanks `peerschuett` for supporting AI Studio financially. +- Added multiple workspace display options: toggle the workspace overlay (this is the previous behavior), toggle the workspace sidebar, or permanently display the workspace sidebar. - Improved the layout of the app window, for example, in full-screen mode on large or high-resolution monitors. - Fixed the "send to" issue, where you could select the bias-of-the-day assistant as destination. \ No newline at end of file