mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-21 10:18:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76dd08ee11 | ||
|
|
c1b92a05fc | ||
|
|
cac2373269 | ||
|
|
f3aa38e090 | ||
|
|
b3b8bf23dc | ||
|
|
a1c4618796 | ||
|
|
0f06b96943 | ||
|
|
d6bd0dc45b | ||
|
|
426f223a84 | ||
|
|
79892eb829 | ||
|
|
d6cf65e973 | ||
|
|
9267ef865d | ||
|
|
4f5815272a | ||
|
|
5250e5d2fb |
No files matched your search
@@ -5,7 +5,7 @@ MindWork AI Studio is a desktop application available for macOS, Windows, and Li
|
|||||||
|
|
||||||
**Key advantages:**
|
**Key advantages:**
|
||||||
- **Free of charge**: The app is free to use, both for personal and commercial purposes.
|
- **Free of charge**: The app is free to use, both for personal and commercial purposes.
|
||||||
- **Independence**: Users are not tied to any single provider. Instead, they can choose the provider that best suits their needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using [llama.cpp](https://github.com/ggerganov/llama.cpp), [ollama](https://github.com/ollama/ollama), or [LM Studio](https://lmstudio.ai/). Support for Google Gemini, [Replicate](https://replicate.com/), and [Fireworks](https://fireworks.ai/) is planned.
|
- **Independence**: You are not tied to any single provider. Instead, you can choose the provider that best suits their needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using [llama.cpp](https://github.com/ggerganov/llama.cpp), [ollama](https://github.com/ollama/ollama), [LM Studio](https://lmstudio.ai/), or [Fireworks](https://fireworks.ai/). Support for Google Gemini, and [Replicate](https://replicate.com/) is planned.
|
||||||
- **Unrestricted usage**: Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API.
|
- **Unrestricted usage**: Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API.
|
||||||
- **Cost-effective**: You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
|
- **Cost-effective**: You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
|
||||||
- **Privacy**: The data entered into the app is not used for training by the providers since we are using the provider's API.
|
- **Privacy**: The data entered into the app is not used for training by the providers since we are using the provider's API.
|
||||||
|
|||||||
@@ -15,21 +15,7 @@
|
|||||||
@this.Body
|
@this.Body
|
||||||
}
|
}
|
||||||
</MudForm>
|
</MudForm>
|
||||||
|
<Issues IssuesData="@this.inputIssues"/>
|
||||||
@if (this.inputIssues.Any())
|
|
||||||
{
|
|
||||||
<MudPaper Class="pr-2 mt-3" Outlined="@true">
|
|
||||||
<MudText Typo="Typo.h6">Issues</MudText>
|
|
||||||
<MudList Clickable="@true">
|
|
||||||
@foreach (var issue in this.inputIssues)
|
|
||||||
{
|
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
|
|
||||||
@issue
|
|
||||||
</MudListItem>
|
|
||||||
}
|
|
||||||
</MudList>
|
|
||||||
</MudPaper>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (this.resultingContentBlock is not null)
|
@if (this.resultingContentBlock is not null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ public partial class Changelog
|
|||||||
|
|
||||||
public static readonly Log[] LOGS =
|
public static readonly Log[] LOGS =
|
||||||
[
|
[
|
||||||
|
new (167, "v0.8.5, build 167 (2024-07-28 16:44 UTC)", "v0.8.5.md"),
|
||||||
|
new (166, "v0.8.4, build 166 (2024-07-26 06:53 UTC)", "v0.8.4.md"),
|
||||||
|
new (165, "v0.8.3, build 165 (2024-07-25 13:25 UTC)", "v0.8.3.md"),
|
||||||
new (164, "v0.8.2, build 164 (2024-07-16 18:03 UTC)", "v0.8.2.md"),
|
new (164, "v0.8.2, build 164 (2024-07-16 18:03 UTC)", "v0.8.2.md"),
|
||||||
new (163, "v0.8.1, build 163 (2024-07-16 08:32 UTC)", "v0.8.1.md"),
|
new (163, "v0.8.1, build 163 (2024-07-16 08:32 UTC)", "v0.8.1.md"),
|
||||||
new (162, "v0.8.0, build 162 (2024-07-14 19:39 UTC)", "v0.8.0.md"),
|
new (162, "v0.8.0, build 162 (2024-07-14 19:39 UTC)", "v0.8.0.md"),
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@inherits ConfigurationBase
|
||||||
|
|
||||||
|
<MudField Disabled="@this.Disabled()" Label="@this.OptionDescription" Variant="Variant.Outlined" HelperText="@this.OptionHelp" Class="@MARGIN_CLASS">
|
||||||
|
<MudSwitch T="bool" Disabled="@this.Disabled()" Value="@this.State()" ValueChanged="@this.OptionChanged" Color="Color.Primary">
|
||||||
|
@(this.State() ? this.LabelOn : this.LabelOff)
|
||||||
|
</MudSwitch>
|
||||||
|
</MudField>
|
||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components;
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration component for any boolean option.
|
/// Configuration component for any boolean option.
|
||||||
@@ -35,5 +35,6 @@ public partial class ConfigurationOption : ConfigurationBase
|
|||||||
{
|
{
|
||||||
this.StateUpdate(updatedState);
|
this.StateUpdate(updatedState);
|
||||||
await this.SettingsManager.StoreSettings();
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.InformAboutChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<ConfigurationSelect OptionDescription="Preselected provider" Disabled="@this.Disabled" OptionHelp="Select a provider that is preselected." Data="@this.Data" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
|
public partial class ConfigurationProviderSelection : ComponentBase, IMessageBusReceiver, IDisposable
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public Func<string> SelectedValue { get; set; } = () => string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Action<string> SelectionUpdate { get; set; } = _ => { };
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public IEnumerable<ConfigurationSelectData<string>> Data { get; set; } = new List<ConfigurationSelectData<string>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the selection component disabled?
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<bool> Disabled { get; set; } = () => false;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private SettingsManager SettingsManager { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private MessageBus MessageBus { get; init; } = null!;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
// Register this component with the message bus:
|
||||||
|
this.MessageBus.RegisterComponent(this);
|
||||||
|
this.MessageBus.ApplyFilters(this, [], [ Event.CONFIGURATION_CHANGED ]);
|
||||||
|
|
||||||
|
await base.OnParametersSetAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation of IMessageBusReceiver
|
||||||
|
|
||||||
|
public async Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||||
|
{
|
||||||
|
switch (triggeredEvent)
|
||||||
|
{
|
||||||
|
case Event.CONFIGURATION_CHANGED:
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(this.SelectedValue()))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Check if the selected value is still valid:
|
||||||
|
if (this.Data.All(x => x.Value != this.SelectedValue()))
|
||||||
|
{
|
||||||
|
this.SelectedValue = () => string.Empty;
|
||||||
|
this.SelectionUpdate(string.Empty);
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.StateHasChanged();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||||
|
{
|
||||||
|
return Task.FromResult<TResult?>(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation of IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.MessageBus.Unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
@inherits ConfigurationBase
|
||||||
|
@typeparam T
|
||||||
|
|
||||||
|
<MudSelect T="T" Value="@this.SelectedValue()" Strict="@true" Disabled="@this.Disabled()" Margin="Margin.Dense" Label="@this.OptionDescription" Class="@GetClass" Variant="Variant.Outlined" HelperText="@this.OptionHelp" ValueChanged="@this.OptionChanged">
|
||||||
|
@foreach (var data in this.Data)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@data.Value">
|
||||||
|
@data.Name
|
||||||
|
</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
+4
-1
@@ -1,6 +1,8 @@
|
|||||||
|
using AIStudio.Settings;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components;
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration component for selecting a value from a list.
|
/// Configuration component for selecting a value from a list.
|
||||||
@@ -30,6 +32,7 @@ public partial class ConfigurationSelect<T> : ConfigurationBase
|
|||||||
{
|
{
|
||||||
this.SelectionUpdate(updatedValue);
|
this.SelectionUpdate(updatedValue);
|
||||||
await this.SettingsManager.StoreSettings();
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.InformAboutChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetClass => $"{MARGIN_CLASS} rounded-lg";
|
private static string GetClass => $"{MARGIN_CLASS} rounded-lg";
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@typeparam T
|
||||||
|
@inherits ConfigurationBase
|
||||||
|
|
||||||
|
<MudField Label="@this.OptionDescription" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.Disabled()">
|
||||||
|
<MudSlider T="@T" Size="Size.Medium" Value="@this.Value()" ValueChanged="@this.OptionChanged" Min="@this.Min" Max="@this.Max" Step="@this.Step" Immediate="@true" Disabled="@this.Disabled()">
|
||||||
|
@this.Value() @this.Unit
|
||||||
|
</MudSlider>
|
||||||
|
</MudField>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
|
public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct, INumber<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum value for the slider.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public T Min { get; set; } = T.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum value for the slider.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public T Max { get; set; } = T.One;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The step size for the slider.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public T Step { get; set; } = T.One;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unit to display next to the slider's value.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string Unit { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value used for the slider.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<T> Value { get; set; } = () => T.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An action which is called when the option is changed.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Action<T> ValueUpdate { get; set; } = _ => { };
|
||||||
|
|
||||||
|
private async Task OptionChanged(T updatedValue)
|
||||||
|
{
|
||||||
|
this.ValueUpdate(updatedValue);
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.InformAboutChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
@inherits ConfigurationBase
|
||||||
|
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
Text="@this.Text()"
|
||||||
|
TextChanged="@this.OptionChanged"
|
||||||
|
Label="@this.OptionDescription"
|
||||||
|
Disabled="@this.Disabled()"
|
||||||
|
Class="mb-3"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@this.Icon"
|
||||||
|
AdornmentColor="@this.IconColor"
|
||||||
|
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||||
|
Lines="1"
|
||||||
|
Immediate="@false"
|
||||||
|
DebounceInterval="500"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
/>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
|
public partial class ConfigurationText : ConfigurationBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The text used for the textfield.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<string> Text { get; set; } = () => string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An action which is called when the option is changed.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Action<string> TextUpdate { get; set; } = _ => { };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The icon to display next to the textfield.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string Icon { get; set; } = Icons.Material.Filled.Info;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The color of the icon to use.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Color IconColor { get; set; } = Color.Default;
|
||||||
|
|
||||||
|
private async Task OptionChanged(string updatedText)
|
||||||
|
{
|
||||||
|
this.TextUpdate(updatedText);
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.InformAboutChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<MudExpansionPanel Class="border-solid border rounded-lg" IsInitiallyExpanded="@this.IsExpanded">
|
<MudExpansionPanel Class="border-solid border rounded-lg" Expanded="@this.IsExpanded">
|
||||||
<TitleContent>
|
<TitleContent>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/>
|
<MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
@if (this.IssuesData.Any())
|
||||||
|
{
|
||||||
|
<MudPaper Class="pa-3 mr-3 mt-3 border-dashed border rounded-lg mud-alert-outlined-error">
|
||||||
|
<MudText Typo="Typo.h6">Issues</MudText>
|
||||||
|
<MudList T="string">
|
||||||
|
@foreach (var issue in this.IssuesData)
|
||||||
|
{
|
||||||
|
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
|
||||||
|
@issue
|
||||||
|
</MudListItem>
|
||||||
|
}
|
||||||
|
</MudList>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Components.Blocks;
|
||||||
|
|
||||||
|
public partial class Issues : ComponentBase
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public IEnumerable<string> IssuesData { get; set; } = [];
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<MudList Clickable="@this.Clickable" Class="@this.Classes">
|
<MudList T="string" ReadOnly="@(!this.Clickable)" Class="@this.Classes">
|
||||||
@foreach(var item in this.Items)
|
@foreach(var item in this.Items)
|
||||||
{
|
{
|
||||||
<MudListItem Icon="@this.Icon" Style="display: flex; align-items: flex-start;">
|
<MudListItem T="string" Icon="@this.Icon" Style="display: flex; align-items: flex-start;">
|
||||||
<MudText Typo="Typo.body1" Style="text-align: justify; hyphens: auto;"><b>@item.Header:</b> @item.Text</MudText>
|
<MudText Typo="Typo.body1" Style="text-align: justify; hyphens: auto;"><b>@item.Header:</b> @item.Text</MudText>
|
||||||
</MudListItem>
|
</MudListItem>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ public class TreeItemData : ITreeItem
|
|||||||
|
|
||||||
public bool Expandable { get; init; } = true;
|
public bool Expandable { get; init; } = true;
|
||||||
|
|
||||||
public HashSet<ITreeItem> Children { get; init; } = [];
|
public IReadOnlyCollection<TreeItemData<ITreeItem>> Children { get; init; } = [];
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<MudTreeView T="ITreeItem" Items="@this.treeItems" MultiSelection="@false" Hover="@true" ExpandOnClick="@true">
|
<MudTreeView T="ITreeItem" Items="@this.treeItems" SelectionMode="SelectionMode.SingleSelection" Hover="@true" ExpandOnClick="@true">
|
||||||
<ItemTemplate Context="item">
|
<ItemTemplate Context="item">
|
||||||
@switch (item)
|
@switch (item.Value)
|
||||||
{
|
{
|
||||||
case TreeDivider:
|
case TreeDivider:
|
||||||
<li style="min-height: 1em;">
|
<li style="min-height: 1em;">
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
case TreeItemData treeItem:
|
case TreeItemData treeItem:
|
||||||
@if (treeItem.Type is TreeItemType.CHAT)
|
@if (treeItem.Type is TreeItemType.CHAT)
|
||||||
{
|
{
|
||||||
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)">
|
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)">
|
||||||
<BodyContent>
|
<BodyContent>
|
||||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||||
<MudText Style="justify-self: start;">
|
<MudText Style="justify-self: start;">
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
}
|
}
|
||||||
else if (treeItem.Type is TreeItemType.WORKSPACE)
|
else if (treeItem.Type is TreeItemType.WORKSPACE)
|
||||||
{
|
{
|
||||||
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
|
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
|
||||||
<BodyContent>
|
<BodyContent>
|
||||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||||
<MudText Style="justify-self: start;">@treeItem.Text</MudText>
|
<MudText Style="justify-self: start;">@treeItem.Text</MudText>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
|
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
|
||||||
<BodyContent>
|
<BodyContent>
|
||||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||||
<MudText Style="justify-self: start;">@treeItem.Text</MudText>
|
<MudText Style="justify-self: start;">@treeItem.Text</MudText>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly HashSet<ITreeItem> treeItems = new();
|
private readonly List<TreeItemData<ITreeItem>> treeItems = new();
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
@@ -70,7 +70,10 @@ public partial class Workspaces : ComponentBase
|
|||||||
private async Task LoadTreeItems()
|
private async Task LoadTreeItems()
|
||||||
{
|
{
|
||||||
this.treeItems.Clear();
|
this.treeItems.Clear();
|
||||||
this.treeItems.Add(new TreeItemData
|
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = true,
|
||||||
|
Value = new TreeItemData
|
||||||
{
|
{
|
||||||
Depth = 0,
|
Depth = 0,
|
||||||
Branch = WorkspaceBranch.WORKSPACES,
|
Branch = WorkspaceBranch.WORKSPACES,
|
||||||
@@ -79,10 +82,19 @@ public partial class Workspaces : ComponentBase
|
|||||||
Expandable = true,
|
Expandable = true,
|
||||||
Path = "root",
|
Path = "root",
|
||||||
Children = await this.LoadWorkspaces(),
|
Children = await this.LoadWorkspaces(),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.treeItems.Add(new TreeDivider());
|
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||||
this.treeItems.Add(new TreeItemData
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = new TreeDivider(),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = true,
|
||||||
|
Value = new TreeItemData
|
||||||
{
|
{
|
||||||
Depth = 0,
|
Depth = 0,
|
||||||
Branch = WorkspaceBranch.TEMPORARY_CHATS,
|
Branch = WorkspaceBranch.TEMPORARY_CHATS,
|
||||||
@@ -91,12 +103,13 @@ public partial class Workspaces : ComponentBase
|
|||||||
Expandable = true,
|
Expandable = true,
|
||||||
Path = "temp",
|
Path = "temp",
|
||||||
Children = await this.LoadTemporaryChats(),
|
Children = await this.LoadTemporaryChats(),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<HashSet<ITreeItem>> LoadTemporaryChats()
|
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadTemporaryChats()
|
||||||
{
|
{
|
||||||
var tempChildren = new HashSet<ITreeItem>();
|
var tempChildren = new List<TreeItemData<ITreeItem>>();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Search for workspace folders in the data directory:
|
// Search for workspace folders in the data directory:
|
||||||
@@ -115,7 +128,10 @@ public partial class Workspaces : ComponentBase
|
|||||||
var chatNamePath = Path.Join(tempChatDirPath, "name");
|
var chatNamePath = Path.Join(tempChatDirPath, "name");
|
||||||
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
||||||
|
|
||||||
tempChildren.Add(new TreeItemData
|
tempChildren.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = new TreeItemData
|
||||||
{
|
{
|
||||||
Type = TreeItemType.CHAT,
|
Type = TreeItemType.CHAT,
|
||||||
Depth = 1,
|
Depth = 1,
|
||||||
@@ -124,6 +140,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
Icon = Icons.Material.Filled.Timer,
|
Icon = Icons.Material.Filled.Timer,
|
||||||
Expandable = false,
|
Expandable = false,
|
||||||
Path = tempChatDirPath,
|
Path = tempChatDirPath,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,9 +157,9 @@ public partial class Workspaces : ComponentBase
|
|||||||
return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
|
return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<HashSet<ITreeItem>> LoadWorkspaces()
|
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaces()
|
||||||
{
|
{
|
||||||
var workspaces = new HashSet<ITreeItem>();
|
var workspaces = new List<TreeItemData<ITreeItem>>();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Search for workspace folders in the data directory:
|
// Search for workspace folders in the data directory:
|
||||||
@@ -161,7 +178,10 @@ public partial class Workspaces : ComponentBase
|
|||||||
var workspaceNamePath = Path.Join(workspaceDirPath, "name");
|
var workspaceNamePath = Path.Join(workspaceDirPath, "name");
|
||||||
var workspaceName = await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
|
var workspaceName = await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
|
||||||
|
|
||||||
workspaces.Add(new TreeItemData
|
workspaces.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = true,
|
||||||
|
Value = new TreeItemData
|
||||||
{
|
{
|
||||||
Type = TreeItemType.WORKSPACE,
|
Type = TreeItemType.WORKSPACE,
|
||||||
Depth = 1,
|
Depth = 1,
|
||||||
@@ -171,16 +191,21 @@ public partial class Workspaces : ComponentBase
|
|||||||
Expandable = true,
|
Expandable = true,
|
||||||
Path = workspaceDirPath,
|
Path = workspaceDirPath,
|
||||||
Children = await this.LoadWorkspaceChats(workspaceDirPath),
|
Children = await this.LoadWorkspaceChats(workspaceDirPath),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaces.Add(new TreeButton(WorkspaceBranch.WORKSPACES, 1, "Add workspace",Icons.Material.Filled.LibraryAdd, this.AddWorkspace));
|
workspaces.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 1, "Add workspace",Icons.Material.Filled.LibraryAdd, this.AddWorkspace),
|
||||||
|
});
|
||||||
return workspaces;
|
return workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<HashSet<ITreeItem>> LoadWorkspaceChats(string workspacePath)
|
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaceChats(string workspacePath)
|
||||||
{
|
{
|
||||||
var workspaceChats = new HashSet<ITreeItem>();
|
var workspaceChats = new List<TreeItemData<ITreeItem>>();
|
||||||
|
|
||||||
// Enumerate the workspace directory:
|
// Enumerate the workspace directory:
|
||||||
foreach (var chatPath in Directory.EnumerateDirectories(workspacePath))
|
foreach (var chatPath in Directory.EnumerateDirectories(workspacePath))
|
||||||
@@ -189,7 +214,10 @@ public partial class Workspaces : ComponentBase
|
|||||||
var chatNamePath = Path.Join(chatPath, "name");
|
var chatNamePath = Path.Join(chatPath, "name");
|
||||||
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
||||||
|
|
||||||
workspaceChats.Add(new TreeItemData
|
workspaceChats.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = new TreeItemData
|
||||||
{
|
{
|
||||||
Type = TreeItemType.CHAT,
|
Type = TreeItemType.CHAT,
|
||||||
Depth = 2,
|
Depth = 2,
|
||||||
@@ -198,10 +226,16 @@ public partial class Workspaces : ComponentBase
|
|||||||
Icon = Icons.Material.Filled.Chat,
|
Icon = Icons.Material.Filled.Chat,
|
||||||
Expandable = false,
|
Expandable = false,
|
||||||
Path = chatPath,
|
Path = chatPath,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceChats.Add(new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath)));
|
workspaceChats.Add(new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath)),
|
||||||
|
});
|
||||||
|
|
||||||
return workspaceChats;
|
return workspaceChats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +281,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Load Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Load Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +328,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +365,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
chat.Name = (dialogResult.Data as string)!;
|
chat.Name = (dialogResult.Data as string)!;
|
||||||
@@ -356,7 +390,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var alteredWorkspaceName = (dialogResult.Data as string)!;
|
var alteredWorkspaceName = (dialogResult.Data as string)!;
|
||||||
@@ -377,7 +411,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Add Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Add Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var workspaceId = Guid.NewGuid();
|
var workspaceId = Guid.NewGuid();
|
||||||
@@ -408,7 +442,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Directory.Delete(workspacePath, true);
|
Directory.Delete(workspacePath, true);
|
||||||
@@ -430,7 +464,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var workspaceId = dialogResult.Data is Guid id ? id : default;
|
var workspaceId = dialogResult.Data is Guid id ? id : default;
|
||||||
@@ -475,7 +509,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Create Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Create Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudText Typo="Typo.body1">@this.Message</MudText>
|
<MudText Typo="Typo.body1">@this.Message</MudText>
|
||||||
<MudTextField T="string" @bind-Text="@this.UserInput" Variant="Variant.Outlined" AutoGrow="@false" Lines="1" Label="Chat name" AutoFocus="@true"/>
|
<MudTextField T="string" @bind-Text="@this.UserInput" Variant="Variant.Outlined" AutoGrow="@false" Lines="1" Label="Chat name" AutoFocus="@true" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton>
|
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using AIStudio.Settings;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.CommonDialogs;
|
namespace AIStudio.Components.CommonDialogs;
|
||||||
@@ -19,6 +21,22 @@ public partial class SingleInputDialog : ComponentBase
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public Color ConfirmColor { get; set; } = Color.Error;
|
public Color ConfirmColor { get; set; } = Color.Error;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private SettingsManager SettingsManager { get; set; } = null!;
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
// Configure the spellchecking for the user input:
|
||||||
|
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private void Cancel() => this.MudDialog.Cancel();
|
private void Cancel() => this.MudDialog.Cancel();
|
||||||
|
|
||||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.UserInput));
|
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.UserInput));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudText Typo="Typo.body1">@this.Message</MudText>
|
<MudText Typo="Typo.body1">@this.Message</MudText>
|
||||||
<MudList Clickable="@true" @bind-SelectedValue="@this.selectedWorkspace">
|
<MudList T="Guid" @bind-SelectedValue="@this.selectedWorkspace">
|
||||||
@foreach (var (workspaceName, workspaceId) in this.workspaces)
|
@foreach (var (workspaceName, workspaceId) in this.workspaces)
|
||||||
{
|
{
|
||||||
<MudListItem Text="@workspaceName" Icon="@Icons.Material.Filled.Description" Value="@workspaceId" />
|
<MudListItem Text="@workspaceName" Icon="@Icons.Material.Filled.Description" Value="@workspaceId" />
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public partial class WorkspaceSelectionDialog : ComponentBase
|
|||||||
public string ConfirmText { get; set; } = "OK";
|
public string ConfirmText { get; set; } = "OK";
|
||||||
|
|
||||||
private readonly Dictionary<string, Guid> workspaces = new();
|
private readonly Dictionary<string, Guid> workspaces = new();
|
||||||
private object? selectedWorkspace;
|
private Guid selectedWorkspace;
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
@@ -56,5 +56,5 @@ public partial class WorkspaceSelectionDialog : ComponentBase
|
|||||||
|
|
||||||
private void Cancel() => this.MudDialog.Cancel();
|
private void Cancel() => this.MudDialog.Cancel();
|
||||||
|
|
||||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.selectedWorkspace is Guid workspaceId ? workspaceId : default));
|
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.selectedWorkspace));
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ namespace AIStudio.Components;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A base class for configuration options.
|
/// A base class for configuration options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ConfigurationBase : ComponentBase
|
public partial class ConfigurationBase : ComponentBase, IMessageBusReceiver, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The description of the option, i.e., the name. Should be
|
/// The description of the option, i.e., the name. Should be
|
||||||
@@ -22,8 +23,66 @@ public partial class ConfigurationBase : ComponentBase
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string OptionHelp { get; set; } = string.Empty;
|
public string OptionHelp { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the option disabled?
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<bool> Disabled { get; set; } = () => false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public SettingsManager SettingsManager { get; init; } = null!;
|
protected SettingsManager SettingsManager { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected MessageBus MessageBus { get; init; } = null!;
|
||||||
|
|
||||||
protected const string MARGIN_CLASS = "mb-6";
|
protected const string MARGIN_CLASS = "mb-6";
|
||||||
|
protected 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);
|
||||||
|
|
||||||
|
// Register this component with the message bus:
|
||||||
|
this.MessageBus.RegisterComponent(this);
|
||||||
|
this.MessageBus.ApplyFilters(this, [], [ Event.CONFIGURATION_CHANGED ]);
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected async Task InformAboutChange() => await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
|
||||||
|
#region Implementation of IMessageBusReceiver
|
||||||
|
|
||||||
|
public Task ProcessMessage<TMsg>(ComponentBase? sendingComponent, Event triggeredEvent, TMsg? data)
|
||||||
|
{
|
||||||
|
switch (triggeredEvent)
|
||||||
|
{
|
||||||
|
case Event.CONFIGURATION_CHANGED:
|
||||||
|
this.StateHasChanged();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||||
|
{
|
||||||
|
return Task.FromResult<TResult?>(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation of IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.MessageBus.Unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
@inherits ConfigurationBase
|
|
||||||
|
|
||||||
<MudField Label="@this.OptionDescription" Variant="Variant.Outlined" HelperText="@this.OptionHelp" Class="@MARGIN_CLASS">
|
|
||||||
<MudSwitch T="bool" Value="@this.State()" ValueChanged="@(updatedState => this.OptionChanged(updatedState))">
|
|
||||||
@(this.State() ? this.LabelOn : this.LabelOff)
|
|
||||||
</MudSwitch>
|
|
||||||
</MudField>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
@inherits ConfigurationBase
|
|
||||||
@typeparam T
|
|
||||||
|
|
||||||
<MudSelect T="T" Value="@this.SelectedValue()" Margin="Margin.Dense" Label="@this.OptionDescription" Class="@GetClass" Variant="Variant.Outlined" HelperText="@this.OptionHelp" ValueChanged="selectedValue => this.OptionChanged(selectedValue)">
|
|
||||||
@foreach (var data in this.Data)
|
|
||||||
{
|
|
||||||
<MudSelectItem Value="@data.Value">
|
|
||||||
@data.Name
|
|
||||||
</MudSelectItem>
|
|
||||||
}
|
|
||||||
</MudSelect>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
@inherits ConfigurationBase
|
|
||||||
|
|
||||||
<MudField Label="@this.OptionDescription" Variant="Variant.Outlined" HelperText="@this.OptionHelp" Class="@MARGIN_CLASS">
|
|
||||||
<MudButton Variant="Variant.Filled" StartIcon="@this.TriggerIcon" OnClick="@this.Click">
|
|
||||||
@this.TriggerText
|
|
||||||
</MudButton>
|
|
||||||
</MudField>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
|
|
||||||
namespace AIStudio.Components;
|
|
||||||
|
|
||||||
public partial class ConfigurationTrigger : ConfigurationBase
|
|
||||||
{
|
|
||||||
[Parameter]
|
|
||||||
public string TriggerText { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string TriggerIcon { get; set; } = Icons.Material.Filled.AddBox;
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public Action OnClickSync { get; set; } = () => { };
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public Func<Task> OnClickAsync { get; set; } = () => Task.CompletedTask;
|
|
||||||
|
|
||||||
private async Task Click()
|
|
||||||
{
|
|
||||||
this.OnClickSync();
|
|
||||||
await this.OnClickAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +1,32 @@
|
|||||||
@inherits LayoutComponentBase
|
@using AIStudio.Settings.DataModel
|
||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<MudPaper Height="calc(100vh);" Elevation="0">
|
<MudPaper Height="calc(100vh);" Elevation="0">
|
||||||
<MudLayout>
|
<MudLayout>
|
||||||
@if (!this.performingUpdate)
|
@if (!this.performingUpdate)
|
||||||
{
|
{
|
||||||
<MudDrawerContainer Class="mud-height-full absolute">
|
<MudDrawerContainer Class="mud-height-full absolute">
|
||||||
<MudDrawer Elevation="0" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@true" Color="Color.Default">
|
<MudDrawer @bind-Open="@this.navBarOpen" MiniWidth="@NAVBAR_COLLAPSED_WIDTH" Width="@NAVBAR_EXPANDED_WIDTH" Elevation="1" Fixed="@true" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.EXPAND_ON_HOVER)" Color="Color.Default">
|
||||||
<MudNavMenu>
|
<MudNavMenu>
|
||||||
<MudTooltip Text="Home" Placement="Placement.Right">
|
@foreach (var navBarItem in NAV_ITEMS)
|
||||||
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
|
{
|
||||||
</MudTooltip>
|
if (this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.NEVER_EXPAND_USE_TOOLTIPS)
|
||||||
<MudTooltip Text="Chat" Placement="Placement.Right">
|
{
|
||||||
<MudNavLink Href="/chat" Icon="@Icons.Material.Filled.Chat">Chat</MudNavLink>
|
<MudTooltip Text="@navBarItem.Name" Placement="Placement.Right">
|
||||||
</MudTooltip>
|
<MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink>
|
||||||
<MudTooltip Text="Assistants" Placement="Placement.Right">
|
|
||||||
<MudNavLink Href="/assistants" Icon="@Icons.Material.Filled.Apps">Assistants</MudNavLink>
|
|
||||||
</MudTooltip>
|
|
||||||
<MudTooltip Text="Supporters" Placement="Placement.Right">
|
|
||||||
<MudNavLink Href="/supporters" Icon="@Icons.Material.Filled.Favorite" IconColor="Color.Error">Supporters</MudNavLink>
|
|
||||||
</MudTooltip>
|
|
||||||
<MudTooltip Text="About" Placement="Placement.Right">
|
|
||||||
<MudNavLink Href="/about" Icon="@Icons.Material.Filled.Info">About</MudNavLink>
|
|
||||||
</MudTooltip>
|
|
||||||
<MudTooltip Text="Settings" Placement="Placement.Right">
|
|
||||||
<MudNavLink Href="/settings" Icon="@Icons.Material.Filled.Settings">Settings</MudNavLink>
|
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink>
|
||||||
|
}
|
||||||
|
}
|
||||||
</MudNavMenu>
|
</MudNavMenu>
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
</MudDrawerContainer>
|
</MudDrawerContainer>
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudMainContent Class="mud-height-full pt-1">
|
<MudMainContent Class="mud-height-full pt-1" Style="@this.PaddingLeft">
|
||||||
<MudContainer Fixed="@true" Class="mud-height-full" Style="margin-left: 5em; width: calc(100% - 5em);">
|
<MudContainer Fixed="@true" Class="mud-height-full" Style="margin-left: 5em; width: calc(100% - 5em);">
|
||||||
@if (!this.performingUpdate && this.IsUpdateAlertVisible)
|
@if (!this.performingUpdate && this.IsUpdateAlertVisible)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using AIStudio.Components.CommonDialogs;
|
using AIStudio.Components.CommonDialogs;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
@@ -9,7 +10,7 @@ using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
|
|||||||
|
|
||||||
namespace AIStudio.Components.Layout;
|
namespace AIStudio.Components.Layout;
|
||||||
|
|
||||||
public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDisposable
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private IJSRuntime JsRuntime { get; init; } = null!;
|
private IJSRuntime JsRuntime { get; init; } = null!;
|
||||||
@@ -34,12 +35,30 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
|
|
||||||
public string AdditionalHeight { get; private set; } = "0em";
|
public string AdditionalHeight { get; private set; } = "0em";
|
||||||
|
|
||||||
|
private string PaddingLeft => this.navBarOpen ? $"padding-left: {NAVBAR_EXPANDED_WIDTH_INT - NAVBAR_COLLAPSED_WIDTH_INT}em;" : "padding-left: 0em;";
|
||||||
|
|
||||||
|
private const int NAVBAR_COLLAPSED_WIDTH_INT = 4;
|
||||||
|
private const int NAVBAR_EXPANDED_WIDTH_INT = 10;
|
||||||
|
private static readonly string NAVBAR_COLLAPSED_WIDTH = $"{NAVBAR_COLLAPSED_WIDTH_INT}em";
|
||||||
|
private static readonly string NAVBAR_EXPANDED_WIDTH = $"{NAVBAR_EXPANDED_WIDTH_INT}em";
|
||||||
|
|
||||||
|
private bool navBarOpen;
|
||||||
private bool isUpdateAvailable;
|
private bool isUpdateAvailable;
|
||||||
private bool performingUpdate;
|
private bool performingUpdate;
|
||||||
private bool userDismissedUpdate;
|
private bool userDismissedUpdate;
|
||||||
private string updateToVersion = string.Empty;
|
private string updateToVersion = string.Empty;
|
||||||
private UpdateResponse? currentUpdateResponse;
|
private UpdateResponse? currentUpdateResponse;
|
||||||
|
|
||||||
|
private static readonly IReadOnlyCollection<NavBarItem> NAV_ITEMS = new List<NavBarItem>
|
||||||
|
{
|
||||||
|
new("Home", Icons.Material.Filled.Home, Color.Default, "/", true),
|
||||||
|
new("Chat", Icons.Material.Filled.Chat, Color.Default, "/chat", false),
|
||||||
|
new("Assistants", Icons.Material.Filled.Apps, Color.Default ,"/assistants", false),
|
||||||
|
new("Supporters", Icons.Material.Filled.Favorite, Color.Error ,"/supporters", false),
|
||||||
|
new("About", Icons.Material.Filled.Info, Color.Default ,"/about", false),
|
||||||
|
new("Settings", Icons.Material.Filled.Settings, Color.Default ,"/settings", false),
|
||||||
|
};
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
@@ -63,12 +82,16 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
|
|
||||||
// Register this component with the message bus:
|
// Register this component with the message bus:
|
||||||
this.MessageBus.RegisterComponent(this);
|
this.MessageBus.RegisterComponent(this);
|
||||||
this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE ]);
|
this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED ]);
|
||||||
|
|
||||||
// Set the js runtime for the update service:
|
// Set the js runtime for the update service:
|
||||||
UpdateService.SetBlazorDependencies(this.JsRuntime, this.Snackbar);
|
UpdateService.SetBlazorDependencies(this.JsRuntime, this.Snackbar);
|
||||||
TemporaryChatService.Initialize();
|
TemporaryChatService.Initialize();
|
||||||
|
|
||||||
|
// Should the navigation bar be open by default?
|
||||||
|
if(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.ALWAYS_EXPAND)
|
||||||
|
this.navBarOpen = true;
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +119,15 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Event.CONFIGURATION_CHANGED:
|
||||||
|
if(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.ALWAYS_EXPAND)
|
||||||
|
this.navBarOpen = true;
|
||||||
|
else
|
||||||
|
this.navBarOpen = false;
|
||||||
|
|
||||||
|
this.StateHasChanged();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +183,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<UpdateDialog>("Update", dialogParameters, DialogOptions.FULLSCREEN_NO_HEADER);
|
var dialogReference = await this.DialogService.ShowAsync<UpdateDialog>("Update", dialogParameters, DialogOptions.FULLSCREEN_NO_HEADER);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.performingUpdate = true;
|
this.performingUpdate = true;
|
||||||
@@ -170,7 +202,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Leave Chat Page", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Leave Chat Page", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
{
|
{
|
||||||
context.PreventNavigation();
|
context.PreventNavigation();
|
||||||
return;
|
return;
|
||||||
@@ -180,4 +212,13 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
|
|||||||
await MessageBus.INSTANCE.SendMessage<bool>(this, Event.RESET_CHAT_STATE);
|
await MessageBus.INSTANCE.SendMessage<bool>(this, Event.RESET_CHAT_STATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Implementation of IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.MessageBus.Unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Components.Layout;
|
||||||
|
|
||||||
|
public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll);
|
||||||
@@ -9,14 +9,14 @@
|
|||||||
<MudText>
|
<MudText>
|
||||||
The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
|
The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudList Clickable="@true">
|
<MudList T="string" Class="mb-3">
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnetRuntime"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnetRuntime"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
|
||||||
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>
|
<MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>
|
||||||
</MudList>
|
</MudList>
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="() => this.CheckForUpdate()">
|
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="() => this.CheckForUpdate()">
|
||||||
Check for updates
|
Check for updates
|
||||||
|
|||||||
@@ -7,6 +7,6 @@
|
|||||||
<MudGrid>
|
<MudGrid>
|
||||||
<AssistantBlock Name="Icon Finder" Description="Using a LLM to find an icon for a given context." Icon="@Icons.Material.Filled.FindInPage" Link="/assistant/icons"/>
|
<AssistantBlock Name="Icon Finder" Description="Using a LLM to find an icon for a given context." Icon="@Icons.Material.Filled.FindInPage" Link="/assistant/icons"/>
|
||||||
<AssistantBlock Name="Text Summarizer" Description="Using a LLM to summarize a given text." Icon="@Icons.Material.Filled.TextSnippet" Link="/assistant/summarizer"/>
|
<AssistantBlock Name="Text Summarizer" Description="Using a LLM to summarize a given text." Icon="@Icons.Material.Filled.TextSnippet" Link="/assistant/summarizer"/>
|
||||||
<AssistantBlock Name="Translator" Description="Translate text into another language." Icon="@Icons.Material.Filled.Translate" Link="/assistant/translator"/>
|
<AssistantBlock Name="Translation" Description="Translate text into another language." Icon="@Icons.Material.Filled.Translate" Link="/assistant/translation"/>
|
||||||
<AssistantBlock Name="Coding" Description="Get coding and debugging support from a LLM." Icon="@Icons.Material.Filled.Code" Link="/assistant/coding"/>
|
<AssistantBlock Name="Coding" Description="Get coding and debugging support from a LLM." Icon="@Icons.Material.Filled.Code" Link="/assistant/coding"/>
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
@page "/chat"
|
@page "/chat"
|
||||||
@using AIStudio.Chat
|
@using AIStudio.Chat
|
||||||
@using AIStudio.Settings
|
@using AIStudio.Settings
|
||||||
|
@using AIStudio.Settings.DataModel
|
||||||
|
|
||||||
@inherits MSGComponentBase
|
@inherits MSGComponentBase
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@
|
|||||||
|
|
||||||
@if (this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
|
@if (this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
|
||||||
{
|
{
|
||||||
<MudTooltip Text="Move chat to (another) workspace" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
<MudTooltip Text="Move the chat to a workspace, or to another if it is already in one." Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.MoveToInbox" Disabled="@(!this.CanThreadBeSaved)" OnClick="() => this.MoveChatToWorkspace()"/>
|
<MudIconButton Icon="@Icons.Material.Filled.MoveToInbox" Disabled="@(!this.CanThreadBeSaved)" OnClick="() => this.MoveChatToWorkspace()"/>
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using AIStudio.Components.Blocks;
|
|||||||
using AIStudio.Components.CommonDialogs;
|
using AIStudio.Components.CommonDialogs;
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
@@ -235,7 +236,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
var confirmationDialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Unsaved Changes", confirmationDialogParameters, DialogOptions.FULLSCREEN);
|
var confirmationDialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Unsaved Changes", confirmationDialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var confirmationDialogResult = await confirmationDialogReference.Result;
|
var confirmationDialogResult = await confirmationDialogReference.Result;
|
||||||
if (confirmationDialogResult.Canceled)
|
if (confirmationDialogResult is null || confirmationDialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +311,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var workspaceId = dialogResult.Data is Guid id ? id : default;
|
var workspaceId = dialogResult.Data is Guid id ? id : default;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
<MudStack Row="@false" Class="mb-3">
|
<MudStack Row="@false" Class="mb-3">
|
||||||
<MudSwitch T="bool" @bind-Value="@this.provideCompilerMessages">
|
<MudSwitch T="bool" @bind-Value="@this.provideCompilerMessages" Color="Color.Primary">
|
||||||
@(this.provideCompilerMessages ? "Provide compiler messages" : "Provide no compiler messages")
|
@(this.provideCompilerMessages ? "Provide compiler messages" : "Provide no compiler messages")
|
||||||
</MudSwitch>
|
</MudSwitch>
|
||||||
@if (this.provideCompilerMessages)
|
@if (this.provideCompilerMessages)
|
||||||
|
|||||||
@@ -29,6 +29,21 @@ public partial class AssistantCoding : AssistantBaseCore
|
|||||||
private string compilerMessages = string.Empty;
|
private string compilerMessages = string.Empty;
|
||||||
private string questions = string.Empty;
|
private string questions = string.Empty;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.PreselectCodingOptions)
|
||||||
|
{
|
||||||
|
this.provideCompilerMessages = this.SettingsManager.ConfigurationData.PreselectCodingCompilerMessages;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedCodingProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private string? ValidatingCompilerMessages(string checkCompilerMessages)
|
private string? ValidatingCompilerMessages(string checkCompilerMessages)
|
||||||
{
|
{
|
||||||
if(!this.provideCompilerMessages)
|
if(!this.provideCompilerMessages)
|
||||||
@@ -53,6 +68,8 @@ public partial class AssistantCoding : AssistantBaseCore
|
|||||||
this.codingContexts.Add(new()
|
this.codingContexts.Add(new()
|
||||||
{
|
{
|
||||||
Id = $"Context {this.codingContexts.Count + 1}",
|
Id = $"Context {this.codingContexts.Count + 1}",
|
||||||
|
Language = this.SettingsManager.ConfigurationData.PreselectCodingOptions ? this.SettingsManager.ConfigurationData.PreselectedCodingLanguage : default,
|
||||||
|
OtherLanguage = this.SettingsManager.ConfigurationData.PreselectCodingOptions ? this.SettingsManager.ConfigurationData.PreselectedCodingOtherLanguage : string.Empty,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public partial class Home : ComponentBase
|
|||||||
private static readonly TextItem[] ITEMS_ADVANTAGES =
|
private static readonly TextItem[] ITEMS_ADVANTAGES =
|
||||||
[
|
[
|
||||||
new TextItem("Free of charge", "The app is free to use, both for personal and commercial purposes."),
|
new TextItem("Free of charge", "The app is free to use, both for personal and commercial purposes."),
|
||||||
new TextItem("Independence", "You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using llama.cpp, ollama, or LM Studio. Support for Google Gemini, Replicate, and Fireworks is planned."),
|
new TextItem("Independence", "You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using llama.cpp, ollama, LM Studio, or Fireworks. Support for Google Gemini and Replicate is planned."),
|
||||||
new TextItem("Unrestricted usage", "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API."),
|
new TextItem("Unrestricted usage", "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API."),
|
||||||
new TextItem("Cost-effective", "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."),
|
new TextItem("Cost-effective", "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."),
|
||||||
new TextItem("Privacy", "The data entered into the app is not used for training by the providers since we are using the provider's API."),
|
new TextItem("Privacy", "The data entered into the app is not used for training by the providers since we are using the provider's API."),
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using AIStudio.Provider;
|
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.IconFinder;
|
namespace AIStudio.Components.Pages.IconFinder;
|
||||||
|
|
||||||
public partial class AssistantIconFinder : AssistantBaseCore
|
public partial class AssistantIconFinder : AssistantBaseCore
|
||||||
@@ -7,6 +5,21 @@ public partial class AssistantIconFinder : AssistantBaseCore
|
|||||||
private string inputContext = string.Empty;
|
private string inputContext = string.Empty;
|
||||||
private IconSources selectedIconSource;
|
private IconSources selectedIconSource;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.PreselectIconOptions)
|
||||||
|
{
|
||||||
|
this.selectedIconSource = this.SettingsManager.ConfigurationData.PreselectedIconSource;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedIconProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
protected override string Title => "Icon Finder";
|
protected override string Title => "Icon Finder";
|
||||||
|
|
||||||
protected override string Description =>
|
protected override string Description =>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
@page "/settings"
|
@page "/settings"
|
||||||
|
@using AIStudio.Components.Pages.Coding
|
||||||
|
@using AIStudio.Components.Pages.TextSummarizer
|
||||||
@using AIStudio.Provider
|
@using AIStudio.Provider
|
||||||
|
@using AIStudio.Settings
|
||||||
|
@using AIStudio.Tools
|
||||||
@using Host = AIStudio.Provider.SelfHosted.Host
|
@using Host = AIStudio.Provider.SelfHosted.Host
|
||||||
|
|
||||||
<MudText Typo="Typo.h3" Class="mb-12">Settings</MudText>
|
<MudText Typo="Typo.h3" Class="mb-12">Settings</MudText>
|
||||||
@@ -29,11 +33,11 @@
|
|||||||
<MudTd>
|
<MudTd>
|
||||||
@if (context.UsedProvider is not Providers.SELF_HOSTED)
|
@if (context.UsedProvider is not Providers.SELF_HOSTED)
|
||||||
{
|
{
|
||||||
@context.Model
|
@this.GetProviderModelName(context)
|
||||||
}
|
}
|
||||||
else if (context.UsedProvider is Providers.SELF_HOSTED && context.Host is not Host.LLAMACPP)
|
else if (context.UsedProvider is Providers.SELF_HOSTED && context.Host is not Host.LLAMACPP)
|
||||||
{
|
{
|
||||||
@context.Model
|
@this.GetProviderModelName(context)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -41,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd Style="text-align: left;">
|
<MudTd Style="text-align: left;">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.OpenInBrowser" Class="ma-2" Href="@this.GetProviderDashboardURL(context.UsedProvider)" Target="_blank" Disabled="@(context.UsedProvider is Providers.NONE or Providers.SELF_HOSTED)">
|
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.OpenInBrowser" Class="ma-2" Href="@this.GetProviderDashboardURL(context.UsedProvider)" Target="_blank" Disabled="@(!this.HasDashboard(context.UsedProvider))">
|
||||||
Open Dashboard
|
Open Dashboard
|
||||||
</MudButton>
|
</MudButton>
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Edit" Class="ma-2" OnClick="() => this.EditProvider(context)">
|
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Edit" Class="ma-2" OnClick="() => this.EditProvider(context)">
|
||||||
@@ -59,19 +63,71 @@
|
|||||||
<MudText Typo="Typo.h6" Class="mt-3">No providers configured yet.</MudText>
|
<MudText Typo="Typo.h6" Class="mt-3">No providers configured yet.</MudText>
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudButton
|
<MudButton Variant="Variant.Filled" Color="@Color.Primary" StartIcon="@Icons.Material.Filled.AddRoad" Class="mt-3 mb-6" OnClick="@this.AddProvider">
|
||||||
Variant="Variant.Filled" Color="@Color.Primary"
|
|
||||||
StartIcon="@Icons.Material.Filled.AddRoad"
|
|
||||||
Class="mt-3 mb-6" OnClick="@this.AddProvider">
|
|
||||||
Add Provider
|
Add Provider
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
<MudText Typo="Typo.h4" Class="mb-3">Options</MudText>
|
<MudText Typo="Typo.h4" Class="mb-3">App Options</MudText>
|
||||||
<ConfigurationOption OptionDescription="Save energy?" LabelOn="Energy saving is enabled" LabelOff="Energy saving is disabled" State="@(() => this.SettingsManager.ConfigurationData.IsSavingEnergy)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.IsSavingEnergy = updatedState)" OptionHelp="When enabled, streamed content from the AI is updated once every third second. When disabled, streamed content will be updated as soon as it is available."/>
|
<ConfigurationOption OptionDescription="Save energy?" LabelOn="Energy saving is enabled" LabelOff="Energy saving is disabled" State="@(() => this.SettingsManager.ConfigurationData.IsSavingEnergy)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.IsSavingEnergy = updatedState)" OptionHelp="When enabled, streamed content from the AI is updated once every third second. When disabled, streamed content will be updated as soon as it is available."/>
|
||||||
<ConfigurationOption OptionDescription="Enable spellchecking?" LabelOn="Spellchecking is enabled" LabelOff="Spellchecking is disabled" State="@(() => this.SettingsManager.ConfigurationData.EnableSpellchecking)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.EnableSpellchecking = updatedState)" OptionHelp="When enabled, spellchecking will be active in all input fields. Depending on your operating system, errors may not be visually highlighted, but right-clicking may still offer possible corrections." />
|
<ConfigurationOption OptionDescription="Enable spellchecking?" LabelOn="Spellchecking is enabled" LabelOff="Spellchecking is disabled" State="@(() => this.SettingsManager.ConfigurationData.EnableSpellchecking)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.EnableSpellchecking = updatedState)" OptionHelp="When enabled, spellchecking will be active in all input fields. Depending on your operating system, errors may not be visually highlighted, but right-clicking may still offer possible corrections." />
|
||||||
<ConfigurationSelect OptionDescription="Shortcut to send input" SelectedValue="@(() => this.SettingsManager.ConfigurationData.ShortcutSendBehavior)" Data="@ConfigurationSelectDataFactory.GetSendBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.ShortcutSendBehavior = selectedValue)" OptionHelp="Do you want to use any shortcut to send your input?"/>
|
|
||||||
<ConfigurationSelect OptionDescription="Check for updates" SelectedValue="@(() => this.SettingsManager.ConfigurationData.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.UpdateBehavior = selectedValue)" OptionHelp="How often should we check for app updates?"/>
|
<ConfigurationSelect OptionDescription="Check for updates" SelectedValue="@(() => this.SettingsManager.ConfigurationData.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.UpdateBehavior = selectedValue)" OptionHelp="How often should we check for app updates?"/>
|
||||||
|
<ConfigurationSelect OptionDescription="Navigation bar behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.NavigationBehavior)" Data="@ConfigurationSelectDataFactory.GetNavBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.NavigationBehavior = selectedValue)" OptionHelp="Select the desired behavior for the navigation bar."/>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h4" Class="mb-3">Chat Options</MudText>
|
||||||
|
<ConfigurationSelect OptionDescription="Shortcut to send input" SelectedValue="@(() => this.SettingsManager.ConfigurationData.ShortcutSendBehavior)" Data="@ConfigurationSelectDataFactory.GetSendBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.ShortcutSendBehavior = selectedValue)" OptionHelp="Do you want to use any shortcut to send your input?"/>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h4" Class="mb-3">Workspace Options</MudText>
|
||||||
<ConfigurationSelect OptionDescription="Workspace behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior = selectedValue)" OptionHelp="Should we store your chats?"/>
|
<ConfigurationSelect OptionDescription="Workspace behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior = selectedValue)" OptionHelp="Should we store your chats?"/>
|
||||||
<ConfigurationSelect OptionDescription="Workspace maintenance" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageTemporaryMaintenancePolicyData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy = selectedValue)" OptionHelp="If and when should we delete your temporary chats?"/>
|
<ConfigurationSelect OptionDescription="Workspace maintenance" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageTemporaryMaintenancePolicyData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy = selectedValue)" OptionHelp="If and when should we delete your temporary chats?"/>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h4" Class="mb-3">Assistants Options</MudText>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-3">Icon Finder Options</MudText>
|
||||||
|
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||||
|
<ConfigurationOption OptionDescription="Preselect icon options?" LabelOn="Icon options are preselected" LabelOff="No icon options are preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectIconOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectIconOptions = updatedState)" OptionHelp="When enabled, you can preselect the icon options. This is might be useful when you prefer a specific icon source or LLM model."/>
|
||||||
|
<ConfigurationSelect OptionDescription="Preselect the icon source" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectIconOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedIconSource)" Data="@ConfigurationSelectDataFactory.GetIconSourcesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedIconSource = selectedValue)" OptionHelp="Which icon source should be preselected?"/>
|
||||||
|
<ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectIconOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedIconProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedIconProvider = selectedValue)"/>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-3">Translator Options</MudText>
|
||||||
|
<ConfigurationSlider T="int" OptionDescription="How fast should the live translation react?" Min="500" Max="3_000" Step="100" Unit="milliseconds" Value="@(() => this.SettingsManager.ConfigurationData.LiveTranslationDebounceIntervalMilliseconds)" ValueUpdate="@(updatedValue => this.SettingsManager.ConfigurationData.LiveTranslationDebounceIntervalMilliseconds = updatedValue)"/>
|
||||||
|
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||||
|
<ConfigurationOption OptionDescription="Preselect translator options?" LabelOn="Translator options are preselected" LabelOff="No translator options are preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectTranslationOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectTranslationOptions = updatedState)" OptionHelp="When enabled, you can preselect the translator options. This is might be useful when you prefer a specific target language or LLM model."/>
|
||||||
|
<ConfigurationOption OptionDescription="Preselect live translation?" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTranslationOptions)" LabelOn="Live translation is preselected" LabelOff="Live translation is not preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectLiveTranslation)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectLiveTranslation = updatedState)" />
|
||||||
|
<ConfigurationSelect OptionDescription="Preselect the target language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTranslationOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage)" Data="@ConfigurationSelectDataFactory.GetCommonLanguagesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage = selectedValue)" OptionHelp="Which target language should be preselected?"/>
|
||||||
|
@if (this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage is CommonLanguages.OTHER)
|
||||||
|
{
|
||||||
|
<ConfigurationText OptionDescription="Preselect another target language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTranslationOptions)" Icon="@Icons.Material.Filled.Translate" Text="@(() => this.SettingsManager.ConfigurationData.PreselectTranslationOtherLanguage)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.PreselectTranslationOtherLanguage = updatedText)"/>
|
||||||
|
}
|
||||||
|
<ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTranslationOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedTranslationProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedTranslationProvider = selectedValue)"/>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-3">Coding Options</MudText>
|
||||||
|
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||||
|
<ConfigurationOption OptionDescription="Preselect coding options?" LabelOn="Coding options are preselected" LabelOff="No coding options are preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectCodingOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectCodingOptions = updatedState)" OptionHelp="When enabled, you can preselect the coding options. This is might be useful when you prefer a specific programming language or LLM model."/>
|
||||||
|
<ConfigurationOption OptionDescription="Preselect compiler messages?" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectCodingOptions)" LabelOn="Compiler messages are preselected" LabelOff="Compiler messages are not preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectCodingCompilerMessages)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectCodingCompilerMessages = updatedState)" />
|
||||||
|
<ConfigurationSelect OptionDescription="Preselect a programming language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectCodingOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedCodingLanguage)" Data="@ConfigurationSelectDataFactory.GetCommonCodingLanguagesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedCodingLanguage = selectedValue)" OptionHelp="Which programming language should be preselected for added contexts?"/>
|
||||||
|
@if (this.SettingsManager.ConfigurationData.PreselectedCodingLanguage is CommonCodingLanguages.OTHER)
|
||||||
|
{
|
||||||
|
<ConfigurationText OptionDescription="Preselect another programming language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectCodingOptions)" Icon="@Icons.Material.Filled.Code" Text="@(() => this.SettingsManager.ConfigurationData.PreselectedCodingOtherLanguage)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.PreselectedCodingOtherLanguage = updatedText)"/>
|
||||||
|
}
|
||||||
|
<ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectCodingOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedCodingProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedCodingProvider = selectedValue)"/>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-3">Text Summarizer Options</MudText>
|
||||||
|
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||||
|
<ConfigurationOption OptionDescription="Preselect summarizer options?" LabelOn="Summarizer options are preselected" LabelOff="No summarizer options are preselected" State="@(() => this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions = updatedState)" OptionHelp="When enabled, you can preselect the text summarizer options. This is might be useful when you prefer a specific language, complexity, or LLM."/>
|
||||||
|
<ConfigurationSelect OptionDescription="Preselect the target language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage)" Data="@ConfigurationSelectDataFactory.GetCommonLanguagesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage = selectedValue)" OptionHelp="Which target language should be preselected?"/>
|
||||||
|
@if (this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage is CommonLanguages.OTHER)
|
||||||
|
{
|
||||||
|
<ConfigurationText OptionDescription="Preselect another target language" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" Icon="@Icons.Material.Filled.Translate" Text="@(() => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerOtherLanguage)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerOtherLanguage = updatedText)"/>
|
||||||
|
}
|
||||||
|
<ConfigurationSelect OptionDescription="Preselect the summarizer complexity" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerComplexity)" Data="@ConfigurationSelectDataFactory.GetComplexityData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerComplexity = selectedValue)" OptionHelp="Which summarizer complexity should be preselected?"/>
|
||||||
|
@if(this.SettingsManager.ConfigurationData.PreselectedTextSummarizerComplexity is Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS)
|
||||||
|
{
|
||||||
|
<ConfigurationText OptionDescription="Preselect your expertise" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" Icon="@Icons.Material.Filled.Person" Text="@(() => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerExpertInField)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerExpertInField = updatedText)"/>
|
||||||
|
}
|
||||||
|
<ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.PreselectedTextSummarizerProvider = selectedValue)"/>
|
||||||
|
</MudPaper>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
</InnerScrolling>
|
</InnerScrolling>
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using AIStudio.Components.CommonDialogs;
|
using AIStudio.Components.CommonDialogs;
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
|
using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
|
||||||
@@ -9,7 +11,7 @@ using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
|
|||||||
|
|
||||||
namespace AIStudio.Components.Pages;
|
namespace AIStudio.Components.Pages;
|
||||||
|
|
||||||
public partial class Settings : ComponentBase
|
public partial class Settings : ComponentBase, IMessageBusReceiver, IDisposable
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
public SettingsManager SettingsManager { get; init; } = null!;
|
public SettingsManager SettingsManager { get; init; } = null!;
|
||||||
@@ -20,6 +22,25 @@ public partial class Settings : ComponentBase
|
|||||||
[Inject]
|
[Inject]
|
||||||
public IJSRuntime JsRuntime { get; init; } = null!;
|
public IJSRuntime JsRuntime { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected MessageBus MessageBus { get; init; } = null!;
|
||||||
|
|
||||||
|
private readonly List<ConfigurationSelectData<string>> availableProviders = new();
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
// Register this component with the message bus:
|
||||||
|
this.MessageBus.RegisterComponent(this);
|
||||||
|
this.MessageBus.ApplyFilters(this, [], [ Event.CONFIGURATION_CHANGED ]);
|
||||||
|
|
||||||
|
this.UpdateProviders();
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Provider related
|
#region Provider related
|
||||||
|
|
||||||
private async Task AddProvider()
|
private async Task AddProvider()
|
||||||
@@ -31,14 +52,17 @@ public partial class Settings : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Add Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Add Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var addedProvider = (AIStudio.Settings.Provider)dialogResult.Data;
|
var addedProvider = (AIStudio.Settings.Provider)dialogResult.Data!;
|
||||||
addedProvider = addedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ };
|
addedProvider = addedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ };
|
||||||
|
|
||||||
this.SettingsManager.ConfigurationData.Providers.Add(addedProvider);
|
this.SettingsManager.ConfigurationData.Providers.Add(addedProvider);
|
||||||
|
this.UpdateProviders();
|
||||||
|
|
||||||
await this.SettingsManager.StoreSettings();
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EditProvider(AIStudio.Settings.Provider provider)
|
private async Task EditProvider(AIStudio.Settings.Provider provider)
|
||||||
@@ -58,10 +82,10 @@ public partial class Settings : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Edit Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Edit Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var editedProvider = (AIStudio.Settings.Provider)dialogResult.Data;
|
var editedProvider = (AIStudio.Settings.Provider)dialogResult.Data!;
|
||||||
|
|
||||||
// Set the provider number if it's not set. This is important for providers
|
// Set the provider number if it's not set. This is important for providers
|
||||||
// added before we started saving the provider number.
|
// added before we started saving the provider number.
|
||||||
@@ -69,7 +93,10 @@ public partial class Settings : ComponentBase
|
|||||||
editedProvider = editedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ };
|
editedProvider = editedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ };
|
||||||
|
|
||||||
this.SettingsManager.ConfigurationData.Providers[this.SettingsManager.ConfigurationData.Providers.IndexOf(provider)] = editedProvider;
|
this.SettingsManager.ConfigurationData.Providers[this.SettingsManager.ConfigurationData.Providers.IndexOf(provider)] = editedProvider;
|
||||||
|
this.UpdateProviders();
|
||||||
|
|
||||||
await this.SettingsManager.StoreSettings();
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteProvider(AIStudio.Settings.Provider provider)
|
private async Task DeleteProvider(AIStudio.Settings.Provider provider)
|
||||||
@@ -81,7 +108,7 @@ public partial class Settings : ComponentBase
|
|||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Provider", dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
var dialogResult = await dialogReference.Result;
|
var dialogResult = await dialogReference.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var providerInstance = provider.CreateProvider();
|
var providerInstance = provider.CreateProvider();
|
||||||
@@ -91,16 +118,74 @@ public partial class Settings : ComponentBase
|
|||||||
this.SettingsManager.ConfigurationData.Providers.Remove(provider);
|
this.SettingsManager.ConfigurationData.Providers.Remove(provider);
|
||||||
await this.SettingsManager.StoreSettings();
|
await this.SettingsManager.StoreSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.UpdateProviders();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool HasDashboard(Providers provider) => provider switch
|
||||||
|
{
|
||||||
|
Providers.OPEN_AI => true,
|
||||||
|
Providers.MISTRAL => true,
|
||||||
|
Providers.ANTHROPIC => true,
|
||||||
|
Providers.FIREWORKS => true,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
private string GetProviderDashboardURL(Providers provider) => provider switch
|
private string GetProviderDashboardURL(Providers provider) => provider switch
|
||||||
{
|
{
|
||||||
Providers.OPEN_AI => "https://platform.openai.com/usage",
|
Providers.OPEN_AI => "https://platform.openai.com/usage",
|
||||||
Providers.MISTRAL => "https://console.mistral.ai/usage/",
|
Providers.MISTRAL => "https://console.mistral.ai/usage/",
|
||||||
Providers.ANTHROPIC => "https://console.anthropic.com/settings/plans",
|
Providers.ANTHROPIC => "https://console.anthropic.com/settings/plans",
|
||||||
|
Providers.FIREWORKS => "https://fireworks.ai/account/billing",
|
||||||
|
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private string GetProviderModelName(AIStudio.Settings.Provider provider)
|
||||||
|
{
|
||||||
|
const int MAX_LENGTH = 36;
|
||||||
|
var modelName = provider.Model.ToString();
|
||||||
|
return modelName.Length > MAX_LENGTH ? "[...] " + modelName[^Math.Min(MAX_LENGTH, modelName.Length)..] : modelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateProviders()
|
||||||
|
{
|
||||||
|
this.availableProviders.Clear();
|
||||||
|
foreach (var provider in this.SettingsManager.ConfigurationData.Providers)
|
||||||
|
this.availableProviders.Add(new (provider.InstanceName, provider.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation of IMessageBusReceiver
|
||||||
|
|
||||||
|
public Task ProcessMessage<TMsg>(ComponentBase? sendingComponent, Event triggeredEvent, TMsg? data)
|
||||||
|
{
|
||||||
|
switch (triggeredEvent)
|
||||||
|
{
|
||||||
|
case Event.CONFIGURATION_CHANGED:
|
||||||
|
this.StateHasChanged();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||||
|
{
|
||||||
|
return Task.FromResult<TResult?>(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation of IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.MessageBus.Unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
+18
-1
@@ -1,4 +1,3 @@
|
|||||||
using AIStudio.Provider;
|
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
namespace AIStudio.Components.Pages.TextSummarizer;
|
||||||
@@ -30,6 +29,24 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
|||||||
private Complexity selectedComplexity;
|
private Complexity selectedComplexity;
|
||||||
private string expertInField = string.Empty;
|
private string expertInField = string.Empty;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if(this.SettingsManager.ConfigurationData.PreselectTextSummarizerOptions)
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.PreselectedTextSummarizerOtherLanguage;
|
||||||
|
this.selectedComplexity = this.SettingsManager.ConfigurationData.PreselectedTextSummarizerComplexity;
|
||||||
|
this.expertInField = this.SettingsManager.ConfigurationData.PreselectedTextSummarizerExpertInField;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedTextSummarizerProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private string? ValidatingText(string text)
|
private string? ValidatingText(string text)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(text))
|
if(string.IsNullOrWhiteSpace(text))
|
||||||
|
|||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
@page "/assistant/translator"
|
@page "/assistant/translation"
|
||||||
@using AIStudio.Settings
|
@using AIStudio.Settings
|
||||||
@using AIStudio.Tools
|
@using AIStudio.Tools
|
||||||
@inherits AssistantBaseCore
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
<MudField Label="Live translation" Variant="Variant.Outlined" Class="mb-3">
|
<MudField Label="Live translation" Variant="Variant.Outlined" Class="mb-3">
|
||||||
<MudSwitch T="bool" @bind-Value="@this.liveTranslation">
|
<MudSwitch T="bool" @bind-Value="@this.liveTranslation" Color="Color.Primary">
|
||||||
@(this.liveTranslation ? "Live translation" : "No live translation")
|
@(this.liveTranslation ? "Live translation" : "No live translation")
|
||||||
</MudSwitch>
|
</MudSwitch>
|
||||||
</MudField>
|
</MudField>
|
||||||
+20
-4
@@ -1,11 +1,10 @@
|
|||||||
using AIStudio.Provider;
|
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Translator;
|
namespace AIStudio.Components.Pages.Translation;
|
||||||
|
|
||||||
public partial class AssistantTranslator : AssistantBaseCore
|
public partial class AssistantTranslation : AssistantBaseCore
|
||||||
{
|
{
|
||||||
protected override string Title => "Translator";
|
protected override string Title => "Translation";
|
||||||
|
|
||||||
protected override string Description =>
|
protected override string Description =>
|
||||||
"""
|
"""
|
||||||
@@ -26,6 +25,23 @@ public partial class AssistantTranslator : AssistantBaseCore
|
|||||||
private CommonLanguages selectedTargetLanguage;
|
private CommonLanguages selectedTargetLanguage;
|
||||||
private string customTargetLanguage = string.Empty;
|
private string customTargetLanguage = string.Empty;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.PreselectTranslationOptions)
|
||||||
|
{
|
||||||
|
this.liveTranslation = this.SettingsManager.ConfigurationData.PreselectLiveTranslation;
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.PreselectTranslationOtherLanguage;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedTranslationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private string? ValidatingText(string text)
|
private string? ValidatingText(string text)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(text))
|
if(string.IsNullOrWhiteSpace(text))
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Translator;
|
namespace AIStudio.Components.Pages.Translation;
|
||||||
|
|
||||||
public static class CommonLanguageExtension
|
public static class CommonLanguageExtension
|
||||||
{
|
{
|
||||||
@@ -7,4 +7,5 @@
|
|||||||
|
|
||||||
<MudThemeProvider />
|
<MudThemeProvider />
|
||||||
<MudDialogProvider />
|
<MudDialogProvider />
|
||||||
|
<MudPopoverProvider />
|
||||||
<MudSnackbarProvider />
|
<MudSnackbarProvider />
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.6" />
|
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.7" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.20.0" />
|
<PackageReference Include="MudBlazor" Version="7.4.0" />
|
||||||
<PackageReference Include="MudBlazor.Markdown" Version="1.0.2" />
|
<PackageReference Include="MudBlazor.Markdown" Version="1.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace AIStudio.Provider.Fireworks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Fireworks chat request model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Model">Which model to use for chat completion.</param>
|
||||||
|
/// <param name="Messages">The chat messages.</param>
|
||||||
|
/// <param name="Stream">Whether to stream the chat completion.</param>
|
||||||
|
public readonly record struct ChatRequest(
|
||||||
|
string Model,
|
||||||
|
IList<Message> Messages,
|
||||||
|
bool Stream
|
||||||
|
);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace AIStudio.Provider.Fireworks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Chat message model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Content">The text content of the message.</param>
|
||||||
|
/// <param name="Role">The role of the message.</param>
|
||||||
|
public readonly record struct Message(string Content, string Role);
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
using AIStudio.Chat;
|
||||||
|
using AIStudio.Settings;
|
||||||
|
|
||||||
|
namespace AIStudio.Provider.Fireworks;
|
||||||
|
|
||||||
|
public class ProviderFireworks() : BaseProvider("https://api.fireworks.ai/inference/v1/"), IProvider
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
|
};
|
||||||
|
|
||||||
|
#region Implementation of IProvider
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Id => "Fireworks.ai";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string InstanceName { get; set; } = "Fireworks.ai";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async IAsyncEnumerable<string> StreamChatCompletion(IJSRuntime jsRuntime, SettingsManager settings, Model chatModel, ChatThread chatThread, [EnumeratorCancellation] CancellationToken token = default)
|
||||||
|
{
|
||||||
|
// Get the API key:
|
||||||
|
var requestedSecret = await settings.GetAPIKey(jsRuntime, this);
|
||||||
|
if(!requestedSecret.Success)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
// Prepare the system prompt:
|
||||||
|
var systemPrompt = new Message
|
||||||
|
{
|
||||||
|
Role = "system",
|
||||||
|
Content = chatThread.SystemPrompt,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prepare the Fireworks HTTP chat request:
|
||||||
|
var fireworksChatRequest = JsonSerializer.Serialize(new ChatRequest
|
||||||
|
{
|
||||||
|
Model = chatModel.Id,
|
||||||
|
|
||||||
|
// Build the messages:
|
||||||
|
// - First of all the system prompt
|
||||||
|
// - Then none-empty user and AI messages
|
||||||
|
Messages = [systemPrompt, ..chatThread.Blocks.Where(n => n.ContentType is ContentType.TEXT && !string.IsNullOrWhiteSpace((n.Content as ContentText)?.Text)).Select(n => new Message
|
||||||
|
{
|
||||||
|
Role = n.Role switch
|
||||||
|
{
|
||||||
|
ChatRole.USER => "user",
|
||||||
|
ChatRole.AI => "assistant",
|
||||||
|
ChatRole.SYSTEM => "system",
|
||||||
|
|
||||||
|
_ => "user",
|
||||||
|
},
|
||||||
|
|
||||||
|
Content = n.Content switch
|
||||||
|
{
|
||||||
|
ContentText text => text.Text,
|
||||||
|
_ => string.Empty,
|
||||||
|
}
|
||||||
|
}).ToList()],
|
||||||
|
|
||||||
|
// Right now, we only support streaming completions:
|
||||||
|
Stream = true,
|
||||||
|
}, JSON_SERIALIZER_OPTIONS);
|
||||||
|
|
||||||
|
// Build the HTTP post request:
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Post, "chat/completions");
|
||||||
|
|
||||||
|
// Set the authorization header:
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", requestedSecret.Secret);
|
||||||
|
|
||||||
|
// Set the content:
|
||||||
|
request.Content = new StringContent(fireworksChatRequest, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
// Send the request with the ResponseHeadersRead option.
|
||||||
|
// This allows us to read the stream as soon as the headers are received.
|
||||||
|
// This is important because we want to stream the responses.
|
||||||
|
var response = await this.httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token);
|
||||||
|
|
||||||
|
// Open the response stream:
|
||||||
|
var fireworksStream = await response.Content.ReadAsStreamAsync(token);
|
||||||
|
|
||||||
|
// Add a stream reader to read the stream, line by line:
|
||||||
|
var streamReader = new StreamReader(fireworksStream);
|
||||||
|
|
||||||
|
// Read the stream, line by line:
|
||||||
|
while(!streamReader.EndOfStream)
|
||||||
|
{
|
||||||
|
// Check if the token is canceled:
|
||||||
|
if(token.IsCancellationRequested)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
// Read the next line:
|
||||||
|
var line = await streamReader.ReadLineAsync(token);
|
||||||
|
|
||||||
|
// Skip empty lines:
|
||||||
|
if(string.IsNullOrWhiteSpace(line))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip lines that do not start with "data: ". Regard
|
||||||
|
// to the specification, we only want to read the data lines:
|
||||||
|
if(!line.StartsWith("data: ", StringComparison.InvariantCulture))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the line is the end of the stream:
|
||||||
|
if (line.StartsWith("data: [DONE]", StringComparison.InvariantCulture))
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
ResponseStreamLine fireworksResponse;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// We know that the line starts with "data: ". Hence, we can
|
||||||
|
// skip the first 6 characters to get the JSON data after that.
|
||||||
|
var jsonData = line[6..];
|
||||||
|
|
||||||
|
// Deserialize the JSON data:
|
||||||
|
fireworksResponse = JsonSerializer.Deserialize<ResponseStreamLine>(jsonData, JSON_SERIALIZER_OPTIONS);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Skip invalid JSON data:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip empty responses:
|
||||||
|
if(fireworksResponse == default || fireworksResponse.Choices.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Yield the response:
|
||||||
|
yield return fireworksResponse.Choices[0].Delta.Content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async IAsyncEnumerable<ImageURL> StreamImageCompletion(IJSRuntime jsRuntime, SettingsManager settings, Model imageModel, string promptPositive, string promptNegative = FilterOperator.String.Empty, ImageURL referenceImageURL = default, [EnumeratorCancellation] CancellationToken token = default)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IEnumerable<Model>> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, string? apiKeyProvisional = null, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Enumerable.Empty<Model>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IEnumerable<Model>> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, string? apiKeyProvisional = null, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Enumerable.Empty<Model>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace AIStudio.Provider.Fireworks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data model for a line in the response stream, for streaming completions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Id">The id of the response.</param>
|
||||||
|
/// <param name="Object">The object describing the response.</param>
|
||||||
|
/// <param name="Created">The timestamp of the response.</param>
|
||||||
|
/// <param name="Model">The model used for the response.</param>
|
||||||
|
/// <param name="Choices">The choices made by the AI.</param>
|
||||||
|
public readonly record struct ResponseStreamLine(string Id, string Object, uint Created, string Model, IList<Choice> Choices);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data model for a choice made by the AI.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Index">The index of the choice.</param>
|
||||||
|
/// <param name="Delta">The delta text of the choice.</param>
|
||||||
|
public readonly record struct Choice(int Index, Delta Delta);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The delta text of a choice.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Content">The content of the delta text.</param>
|
||||||
|
public readonly record struct Delta(string Content);
|
||||||
@@ -97,7 +97,7 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/"
|
|||||||
// Read the stream, line by line:
|
// Read the stream, line by line:
|
||||||
while(!streamReader.EndOfStream)
|
while(!streamReader.EndOfStream)
|
||||||
{
|
{
|
||||||
// Check if the token is cancelled:
|
// Check if the token is canceled:
|
||||||
if(token.IsCancellationRequested)
|
if(token.IsCancellationRequested)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Provider.Anthropic;
|
using AIStudio.Provider.Anthropic;
|
||||||
|
using AIStudio.Provider.Fireworks;
|
||||||
using AIStudio.Provider.Mistral;
|
using AIStudio.Provider.Mistral;
|
||||||
using AIStudio.Provider.OpenAI;
|
using AIStudio.Provider.OpenAI;
|
||||||
using AIStudio.Provider.SelfHosted;
|
using AIStudio.Provider.SelfHosted;
|
||||||
@@ -10,13 +11,15 @@ namespace AIStudio.Provider;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum Providers
|
public enum Providers
|
||||||
{
|
{
|
||||||
NONE,
|
NONE = 0,
|
||||||
|
|
||||||
OPEN_AI,
|
OPEN_AI = 1,
|
||||||
ANTHROPIC,
|
ANTHROPIC = 2,
|
||||||
MISTRAL,
|
MISTRAL = 3,
|
||||||
|
|
||||||
SELF_HOSTED,
|
FIREWORKS = 5,
|
||||||
|
|
||||||
|
SELF_HOSTED = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -37,6 +40,8 @@ public static class ExtensionsProvider
|
|||||||
Providers.ANTHROPIC => "Anthropic",
|
Providers.ANTHROPIC => "Anthropic",
|
||||||
Providers.MISTRAL => "Mistral",
|
Providers.MISTRAL => "Mistral",
|
||||||
|
|
||||||
|
Providers.FIREWORKS => "Fireworks.ai",
|
||||||
|
|
||||||
Providers.SELF_HOSTED => "Self-hosted",
|
Providers.SELF_HOSTED => "Self-hosted",
|
||||||
|
|
||||||
_ => "Unknown",
|
_ => "Unknown",
|
||||||
@@ -47,14 +52,27 @@ public static class ExtensionsProvider
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="providerSettings">The provider settings.</param>
|
/// <param name="providerSettings">The provider settings.</param>
|
||||||
/// <returns>The provider instance.</returns>
|
/// <returns>The provider instance.</returns>
|
||||||
public static IProvider CreateProvider(this Settings.Provider providerSettings) => providerSettings.UsedProvider switch
|
public static IProvider CreateProvider(this Settings.Provider providerSettings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return providerSettings.UsedProvider switch
|
||||||
{
|
{
|
||||||
Providers.OPEN_AI => new ProviderOpenAI { InstanceName = providerSettings.InstanceName },
|
Providers.OPEN_AI => new ProviderOpenAI { InstanceName = providerSettings.InstanceName },
|
||||||
Providers.ANTHROPIC => new ProviderAnthropic { InstanceName = providerSettings.InstanceName },
|
Providers.ANTHROPIC => new ProviderAnthropic { InstanceName = providerSettings.InstanceName },
|
||||||
Providers.MISTRAL => new ProviderMistral { InstanceName = providerSettings.InstanceName },
|
Providers.MISTRAL => new ProviderMistral { InstanceName = providerSettings.InstanceName },
|
||||||
|
|
||||||
|
Providers.FIREWORKS => new ProviderFireworks { InstanceName = providerSettings.InstanceName },
|
||||||
|
|
||||||
Providers.SELF_HOSTED => new ProviderSelfHosted(providerSettings) { InstanceName = providerSettings.InstanceName },
|
Providers.SELF_HOSTED => new ProviderSelfHosted(providerSettings) { InstanceName = providerSettings.InstanceName },
|
||||||
|
|
||||||
_ => new NoProvider(),
|
_ => new NoProvider(),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to create provider: {e.Message}");
|
||||||
|
return new NoProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+38
-2
@@ -1,6 +1,10 @@
|
|||||||
using AIStudio.Settings;
|
using AIStudio.Components.Pages.Coding;
|
||||||
|
using AIStudio.Components.Pages.IconFinder;
|
||||||
|
using AIStudio.Components.Pages.TextSummarizer;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components;
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A data structure to map a name to a value.
|
/// A data structure to map a name to a value.
|
||||||
@@ -47,4 +51,36 @@ public static class ConfigurationSelectDataFactory
|
|||||||
yield return new("Delete temporary chats older than 180 days", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_180_DAYS);
|
yield return new("Delete temporary chats older than 180 days", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_180_DAYS);
|
||||||
yield return new("Delete temporary chats older than 1 year", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_365_DAYS);
|
yield return new("Delete temporary chats older than 1 year", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_365_DAYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<ConfigurationSelectData<NavBehavior>> GetNavBehaviorData()
|
||||||
|
{
|
||||||
|
yield return new("Navigation expands on mouse hover", NavBehavior.EXPAND_ON_HOVER);
|
||||||
|
yield return new("Navigation never expands, but there are tooltips", NavBehavior.NEVER_EXPAND_USE_TOOLTIPS);
|
||||||
|
yield return new("Navigation never expands, no tooltips", NavBehavior.NEVER_EXPAND_NO_TOOLTIPS);
|
||||||
|
yield return new("Always expand navigation", NavBehavior.ALWAYS_EXPAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<ConfigurationSelectData<IconSources>> GetIconSourcesData()
|
||||||
|
{
|
||||||
|
foreach (var source in Enum.GetValues<IconSources>())
|
||||||
|
yield return new(source.Name(), source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<ConfigurationSelectData<CommonLanguages>> GetCommonLanguagesData()
|
||||||
|
{
|
||||||
|
foreach (var language in Enum.GetValues<CommonLanguages>())
|
||||||
|
yield return new(language.Name(), language);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<ConfigurationSelectData<CommonCodingLanguages>> GetCommonCodingLanguagesData()
|
||||||
|
{
|
||||||
|
foreach (var language in Enum.GetValues<CommonCodingLanguages>())
|
||||||
|
yield return new(language.Name(), language);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<ConfigurationSelectData<Complexity>> GetComplexityData()
|
||||||
|
{
|
||||||
|
foreach (var complexity in Enum.GetValues<Complexity>())
|
||||||
|
yield return new(complexity.Name(), complexity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
namespace AIStudio.Settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data model for the settings file.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class Data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The version of the settings file. Allows us to upgrade the settings
|
|
||||||
/// when a new version is available.
|
|
||||||
/// </summary>
|
|
||||||
public Version Version { get; init; } = Version.V3;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of configured providers.
|
|
||||||
/// </summary>
|
|
||||||
public List<Provider> Providers { get; init; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The next provider number to use.
|
|
||||||
/// </summary>
|
|
||||||
public uint NextProviderNum { get; set; } = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should we save energy? When true, we will update content streamed
|
|
||||||
/// from the server, i.e., AI, less frequently.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsSavingEnergy { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shortcuts to send the input to the AI.
|
|
||||||
/// </summary>
|
|
||||||
public SendBehavior ShortcutSendBehavior { get; set; } = SendBehavior.MODIFER_ENTER_IS_SENDING;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should we enable spellchecking for all input fields?
|
|
||||||
/// </summary>
|
|
||||||
public bool EnableSpellchecking { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If and when we should look for updates.
|
|
||||||
/// </summary>
|
|
||||||
public UpdateBehavior UpdateBehavior { get; set; } = UpdateBehavior.ONCE_STARTUP;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The chat storage behavior.
|
|
||||||
/// </summary>
|
|
||||||
public WorkspaceStorageBehavior WorkspaceStorageBehavior { get; set; } = WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The chat storage maintenance behavior.
|
|
||||||
/// </summary>
|
|
||||||
public WorkspaceStorageTemporaryMaintenancePolicy WorkspaceStorageTemporaryMaintenancePolicy { get; set; } = WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_90_DAYS;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
using AIStudio.Components.Pages.Coding;
|
||||||
|
using AIStudio.Components.Pages.IconFinder;
|
||||||
|
using AIStudio.Components.Pages.TextSummarizer;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data model for the settings file.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The version of the settings file. Allows us to upgrade the settings
|
||||||
|
/// when a new version is available.
|
||||||
|
/// </summary>
|
||||||
|
public Version Version { get; init; } = Version.V3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of configured providers.
|
||||||
|
/// </summary>
|
||||||
|
public List<Provider> Providers { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The next provider number to use.
|
||||||
|
/// </summary>
|
||||||
|
public uint NextProviderNum { get; set; } = 1;
|
||||||
|
|
||||||
|
#region App Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should we save energy? When true, we will update content streamed
|
||||||
|
/// from the server, i.e., AI, less frequently.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSavingEnergy { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should we enable spellchecking for all input fields?
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableSpellchecking { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If and when we should look for updates.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateBehavior UpdateBehavior { get; set; } = UpdateBehavior.ONCE_STARTUP;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The navigation behavior.
|
||||||
|
/// </summary>
|
||||||
|
public NavBehavior NavigationBehavior { get; set; } = NavBehavior.EXPAND_ON_HOVER;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Chat Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shortcuts to send the input to the AI.
|
||||||
|
/// </summary>
|
||||||
|
public SendBehavior ShortcutSendBehavior { get; set; } = SendBehavior.MODIFER_ENTER_IS_SENDING;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Workspace Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chat storage behavior.
|
||||||
|
/// </summary>
|
||||||
|
public WorkspaceStorageBehavior WorkspaceStorageBehavior { get; set; } = WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chat storage maintenance behavior.
|
||||||
|
/// </summary>
|
||||||
|
public WorkspaceStorageTemporaryMaintenancePolicy WorkspaceStorageTemporaryMaintenancePolicy { get; set; } = WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_90_DAYS;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Assiatant: Icon Finder Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do we want to preselect any icon options?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectIconOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The preselected icon source.
|
||||||
|
/// </summary>
|
||||||
|
public IconSources PreselectedIconSource { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The preselected icon provider.
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedIconProvider { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Assistant: Translation Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The live translation interval for debouncing in milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
public int LiveTranslationDebounceIntervalMilliseconds { get; set; } = 1_000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do we want to preselect any translator options?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectTranslationOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the live translation?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectLiveTranslation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the target language?
|
||||||
|
/// </summary>
|
||||||
|
public CommonLanguages PreselectedTranslationTargetLanguage { get; set; } = CommonLanguages.EN_US;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect any other language?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectTranslationOtherLanguage { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The preselected translator provider.
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedTranslationProvider { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Assistant: Coding Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect any coding options?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectCodingOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the compiler messages?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectCodingCompilerMessages { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the coding language for new contexts?
|
||||||
|
/// </summary>
|
||||||
|
public CommonCodingLanguages PreselectedCodingLanguage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do you want to preselect any other language?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedCodingOtherLanguage { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Which coding provider should be preselected?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedCodingProvider { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Assistant: Text Summarizer Settings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect any text summarizer options?
|
||||||
|
/// </summary>
|
||||||
|
public bool PreselectTextSummarizerOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the target language?
|
||||||
|
/// </summary>
|
||||||
|
public CommonLanguages PreselectedTextSummarizerTargetLanguage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect any other language?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedTextSummarizerOtherLanguage { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect the complexity?
|
||||||
|
/// </summary>
|
||||||
|
public Complexity PreselectedTextSummarizerComplexity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect any expertise in a field?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedTextSummarizerExpertInField { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preselect a text summarizer provider?
|
||||||
|
/// </summary>
|
||||||
|
public string PreselectedTextSummarizerProvider { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
|
public enum NavBehavior
|
||||||
|
{
|
||||||
|
EXPAND_ON_HOVER,
|
||||||
|
NEVER_EXPAND_USE_TOOLTIPS,
|
||||||
|
NEVER_EXPAND_NO_TOOLTIPS,
|
||||||
|
ALWAYS_EXPAND,
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Possible behaviors for sending the input to the AI.
|
/// Possible behaviors for sending the input to the AI.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
public enum UpdateBehavior
|
public enum UpdateBehavior
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
public enum WorkspaceStorageBehavior
|
public enum WorkspaceStorageBehavior
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
public enum WorkspaceStorageTemporaryMaintenancePolicy
|
public enum WorkspaceStorageTemporaryMaintenancePolicy
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
@using AIStudio.Provider
|
@using AIStudio.Provider
|
||||||
@using AIStudio.Provider.SelfHosted
|
@using AIStudio.Provider.SelfHosted
|
||||||
@using MudBlazor
|
@using MudBlazor
|
||||||
|
@using AIStudio.Components.Blocks
|
||||||
|
|
||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
<MudSelectItem Value="@provider">@provider</MudSelectItem>
|
<MudSelectItem Value="@provider">@provider</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudButton Disabled="@this.IsSelfHostedOrNone" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.GetProviderCreationURL()" Target="_blank">Create account</MudButton>
|
<MudButton Disabled="@(!this.ShowRegisterButton)" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.GetProviderCreationURL()" Target="_blank">Create account</MudButton>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
T="string"
|
T="string"
|
||||||
@bind-Text="@this.dataAPIKey"
|
@bind-Text="@this.dataAPIKey"
|
||||||
Label="API Key"
|
Label="API Key"
|
||||||
Disabled="@this.IsSelfHostedOrNone"
|
Disabled="@(!this.NeedAPIKey)"
|
||||||
Class="mb-3"
|
Class="mb-3"
|
||||||
Adornment="Adornment.Start"
|
Adornment="Adornment.Start"
|
||||||
AdornmentIcon="@Icons.Material.Filled.VpnKey"
|
AdornmentIcon="@Icons.Material.Filled.VpnKey"
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
T="string"
|
T="string"
|
||||||
@bind-Text="@this.DataHostname"
|
@bind-Text="@this.DataHostname"
|
||||||
Label="Hostname"
|
Label="Hostname"
|
||||||
Disabled="@this.IsCloudProvider"
|
Disabled="@(!this.NeedHostname)"
|
||||||
Class="mb-3"
|
Class="mb-3"
|
||||||
Adornment="Adornment.Start"
|
Adornment="Adornment.Start"
|
||||||
AdornmentIcon="@Icons.Material.Filled.Dns"
|
AdornmentIcon="@Icons.Material.Filled.Dns"
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MudSelect Disabled="@this.IsCloudProvider" @bind-Value="@this.DataHost" Label="Host" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingHost">
|
<MudSelect Disabled="@(!this.NeedHost)" @bind-Value="@this.DataHost" Label="Host" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingHost">
|
||||||
@foreach (Host host in Enum.GetValues(typeof(Host)))
|
@foreach (Host host in Enum.GetValues(typeof(Host)))
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@host">@host.Name()</MudSelectItem>
|
<MudSelectItem Value="@host">@host.Name()</MudSelectItem>
|
||||||
@@ -51,6 +52,23 @@
|
|||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
|
||||||
<MudStack Row="@true" AlignItems="AlignItems.Center">
|
<MudStack Row="@true" AlignItems="AlignItems.Center">
|
||||||
|
@if (this.ProvideModelManually)
|
||||||
|
{
|
||||||
|
<MudButton Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.GetModelOverviewURL()" Target="_blank">Show available models</MudButton>
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
@bind-Text="@this.dataManuallyModel"
|
||||||
|
Label="Model"
|
||||||
|
Class="mb-3"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.Dns"
|
||||||
|
AdornmentColor="Color.Info"
|
||||||
|
Validation="@this.ValidateManuallyModel"
|
||||||
|
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
<MudButton Disabled="@(!this.CanLoadModels())" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
|
<MudButton Disabled="@(!this.CanLoadModels())" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">Load</MudButton>
|
||||||
<MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="Model" Class="mb-3" OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingModel">
|
<MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="Model" Class="mb-3" OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.ValidatingModel">
|
||||||
@foreach (var model in this.availableModels)
|
@foreach (var model in this.availableModels)
|
||||||
@@ -58,6 +76,7 @@
|
|||||||
<MudSelectItem Value="@model">@model</MudSelectItem>
|
<MudSelectItem Value="@model">@model</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
}
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||||
@@ -74,21 +93,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
</MudForm>
|
</MudForm>
|
||||||
|
<Issues IssuesData="@this.dataIssues"/>
|
||||||
@if (this.dataIssues.Any())
|
|
||||||
{
|
|
||||||
<MudPaper Class="pa-2 mt-3">
|
|
||||||
<MudText Typo="Typo.h6">Issues</MudText>
|
|
||||||
<MudList Clickable="@true">
|
|
||||||
@foreach (var issue in this.dataIssues)
|
|
||||||
{
|
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
|
|
||||||
@issue
|
|
||||||
</MudListItem>
|
|
||||||
}
|
|
||||||
</MudList>
|
|
||||||
</MudPaper>
|
|
||||||
}
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton>
|
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton>
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
private bool dataIsValid;
|
private bool dataIsValid;
|
||||||
private string[] dataIssues = [];
|
private string[] dataIssues = [];
|
||||||
private string dataAPIKey = string.Empty;
|
private string dataAPIKey = string.Empty;
|
||||||
|
private string dataManuallyModel = string.Empty;
|
||||||
private string dataAPIKeyStorageIssue = string.Empty;
|
private string dataAPIKeyStorageIssue = string.Empty;
|
||||||
private string dataEditingPreviousInstanceName = string.Empty;
|
private string dataEditingPreviousInstanceName = string.Empty;
|
||||||
|
|
||||||
@@ -100,9 +101,9 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
Id = this.DataId,
|
Id = this.DataId,
|
||||||
InstanceName = this.DataInstanceName,
|
InstanceName = this.DataInstanceName,
|
||||||
UsedProvider = this.DataProvider,
|
UsedProvider = this.DataProvider,
|
||||||
Model = this.DataModel,
|
Model = this.DataProvider is Providers.FIREWORKS ? new Model(this.dataManuallyModel) : this.DataModel,
|
||||||
IsSelfHosted = this.DataProvider is Providers.SELF_HOSTED,
|
IsSelfHosted = this.DataProvider is Providers.SELF_HOSTED,
|
||||||
Hostname = this.DataHostname,
|
Hostname = this.DataHostname.EndsWith('/') ? this.DataHostname[..^1] : this.DataHostname,
|
||||||
Host = this.DataHost,
|
Host = this.DataHost,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -220,6 +221,14 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string? ValidateManuallyModel(string manuallyModel)
|
||||||
|
{
|
||||||
|
if (this.DataProvider is Providers.FIREWORKS && string.IsNullOrWhiteSpace(manuallyModel))
|
||||||
|
return "Please enter a model name.";
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private string? ValidatingModel(Model model)
|
private string? ValidatingModel(Model model)
|
||||||
{
|
{
|
||||||
if(this.DataProvider is Providers.SELF_HOSTED && this.DataHost == Host.LLAMACPP)
|
if(this.DataProvider is Providers.SELF_HOSTED && this.DataHost == Host.LLAMACPP)
|
||||||
@@ -354,11 +363,52 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsCloudProvider => this.DataProvider is not Providers.SELF_HOSTED;
|
private bool ShowRegisterButton => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.OPEN_AI => true,
|
||||||
|
Providers.MISTRAL => true,
|
||||||
|
Providers.ANTHROPIC => true,
|
||||||
|
|
||||||
private bool IsSelfHostedOrNone => this.DataProvider is Providers.SELF_HOSTED or Providers.NONE;
|
Providers.FIREWORKS => true,
|
||||||
|
|
||||||
private bool IsNoneProvider => this.DataProvider is Providers.NONE;
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool NeedAPIKey => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.OPEN_AI => true,
|
||||||
|
Providers.MISTRAL => true,
|
||||||
|
Providers.ANTHROPIC => true,
|
||||||
|
|
||||||
|
Providers.FIREWORKS => true,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool NeedHostname => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.SELF_HOSTED => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool NeedHost => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.SELF_HOSTED => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool ProvideModelManually => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.FIREWORKS => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private string GetModelOverviewURL() => this.DataProvider switch
|
||||||
|
{
|
||||||
|
Providers.FIREWORKS => "https://fireworks.ai/models?show=Serverless",
|
||||||
|
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
|
|
||||||
private string GetProviderCreationURL() => this.DataProvider switch
|
private string GetProviderCreationURL() => this.DataProvider switch
|
||||||
{
|
{
|
||||||
@@ -366,6 +416,10 @@ public partial class ProviderDialog : ComponentBase
|
|||||||
Providers.MISTRAL => "https://console.mistral.ai/",
|
Providers.MISTRAL => "https://console.mistral.ai/",
|
||||||
Providers.ANTHROPIC => "https://console.anthropic.com/dashboard",
|
Providers.ANTHROPIC => "https://console.anthropic.com/dashboard",
|
||||||
|
|
||||||
|
Providers.FIREWORKS => "https://fireworks.ai/login",
|
||||||
|
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private bool IsNoneProvider => this.DataProvider is Providers.NONE;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
// ReSharper disable NotAccessedPositionalProperty.Local
|
// ReSharper disable NotAccessedPositionalProperty.Local
|
||||||
|
|
||||||
@@ -72,9 +73,10 @@ public sealed class SettingsManager
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data structure for deleting a secret response.
|
/// Data structure for deleting a secret response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Success">True, when the secret was successfully deleted.</param>
|
/// <param name="Success">True, when the secret was successfully deleted or not found.</param>
|
||||||
/// <param name="Issue">The issue, when the secret could not be deleted.</param>
|
/// <param name="Issue">The issue, when the secret could not be deleted.</param>
|
||||||
public readonly record struct DeleteSecretResponse(bool Success, string Issue);
|
/// <param name="WasEntryFound">True, when the entry was found and deleted.</param>
|
||||||
|
public readonly record struct DeleteSecretResponse(bool Success, string Issue, bool WasEntryFound);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to delete the API key for the given provider.
|
/// Tries to delete the API key for the given provider.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
using Host = AIStudio.Provider.SelfHosted.Host;
|
using Host = AIStudio.Provider.SelfHosted.Host;
|
||||||
|
|
||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ public enum Event
|
|||||||
|
|
||||||
// Common events:
|
// Common events:
|
||||||
STATE_HAS_CHANGED,
|
STATE_HAS_CHANGED,
|
||||||
|
CONFIGURATION_CHANGED,
|
||||||
|
|
||||||
// Update events:
|
// Update events:
|
||||||
USER_SEARCH_FOR_UPDATE,
|
USER_SEARCH_FOR_UPDATE,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
namespace AIStudio.Tools;
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"net8.0": {
|
"net8.0": {
|
||||||
"Microsoft.Extensions.FileProviders.Embedded": {
|
"Microsoft.Extensions.FileProviders.Embedded": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[8.0.6, )",
|
"requested": "[8.0.7, )",
|
||||||
"resolved": "8.0.6",
|
"resolved": "8.0.7",
|
||||||
"contentHash": "hQlf5+YxiUbKdpaPBf/zdMGItnWF8ai9ToPjeZ6gnxT10V4RGDKvChl5MSdc838+2SRHLAC0cdJwG0+L7dqR0g==",
|
"contentHash": "ABsn0T09b5lzVNbOcuRc10+kNZkO+RGtZWfzqVay0Ah+/ouhEvG7JrXc+9+7zFgoPuH4E4N6+uWfTp+pJqMeGw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
|
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
|
||||||
}
|
}
|
||||||
@@ -19,13 +19,13 @@
|
|||||||
},
|
},
|
||||||
"MudBlazor": {
|
"MudBlazor": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[6.20.0, )",
|
"requested": "[7.4.0, )",
|
||||||
"resolved": "6.20.0",
|
"resolved": "7.4.0",
|
||||||
"contentHash": "2MqW/E1OLszSqDhW06rpRTN4OpIRJU0iVzeiZLPzymckrKJH1Hg09St+O3kaEnsbXRcjcdM9iE5cSKzCgxvySQ==",
|
"contentHash": "dm8ZD6OhyI6icE3Si0V3BJvwPZp8fEspPFq4/iQXU8/i7L39/ny2bPgQqPnQmIojppd9cR/H4RdsaBlSLe6rIw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Components": "8.0.3",
|
"Microsoft.AspNetCore.Components": "8.0.6",
|
||||||
"Microsoft.AspNetCore.Components.Web": "8.0.3",
|
"Microsoft.AspNetCore.Components.Web": "8.0.6",
|
||||||
"Microsoft.Extensions.Localization": "8.0.3"
|
"Microsoft.Extensions.Localization": "8.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MudBlazor.Markdown": {
|
"MudBlazor.Markdown": {
|
||||||
@@ -45,53 +45,53 @@
|
|||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Authorization": {
|
"Microsoft.AspNetCore.Authorization": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "9Nic17acgZbysUlhGc+TEd9F8jI01kC6+V31sC7/xI5v2OSWGL8NhdYaB/Iu4KnDRoQEolg6qvepGsVfeYpIYA==",
|
"contentHash": "H1CSbD7UeSPsrJSUpvbms6SqWMa5y8ch4Rw+gyHh2uztOEb20fTP2r0AUnStn1Q9WYghikiDO5wzkgV+n6KC2Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Metadata": "8.0.3",
|
"Microsoft.AspNetCore.Metadata": "8.0.6",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
|
||||||
"Microsoft.Extensions.Options": "8.0.2"
|
"Microsoft.Extensions.Options": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Components": {
|
"Microsoft.AspNetCore.Components": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "q1Da8sfxG+B+BSYpc/3RKNEdzGcLbDTXkTUqekY65kXMMVCTqTAQ0Zs4csmB7FNVTFSjwaw1dGMFD0bQ+erlBw==",
|
"contentHash": "Je2l+rd5i8gB+ZWsN5wBHOsnyAh81h6+a5vNq6rjfQhM2ZYxH+BVsmanCYa+F8BFy6rmd+ZL61SEiNaAyAOgtg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Authorization": "8.0.3",
|
"Microsoft.AspNetCore.Authorization": "8.0.6",
|
||||||
"Microsoft.AspNetCore.Components.Analyzers": "8.0.3"
|
"Microsoft.AspNetCore.Components.Analyzers": "8.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Components.Analyzers": {
|
"Microsoft.AspNetCore.Components.Analyzers": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "iERLuYM+YFI/K1jkinr1YeAkJYHUcijPiPCKgmgs2ZhJLqiIVJRT08vUtIsfhiFtGiI5MIzK0R1BZHyS3yAQng=="
|
"contentHash": "SEL0CN1jJdJkCDwRox3kSY1ffMnahlOCDJZYrYWfQ6ftjqRuuiPtwyvI3VIeVHLcpT3VP1AXww8wzKDK3oeFxg=="
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Components.Forms": {
|
"Microsoft.AspNetCore.Components.Forms": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "OxY5NDmePnn6FMb+Fum57YL7LCHk3u2Wg0qSln3uZSayo+oIxYuoGnqH2dUMp1P5vOPfq17NKCIIEbxfU2dirQ==",
|
"contentHash": "49wIE1ns3ZGDU4NPMcKCSTC716IxujUeaynsUyflM5Qmb2WlF6M6m4pMcJ6UET1Ixmn027nZjMEc8J7pU4BLBg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Components": "8.0.3"
|
"Microsoft.AspNetCore.Components": "8.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Components.Web": {
|
"Microsoft.AspNetCore.Components.Web": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "bHWJiz/JhjptK3iYzha0Rm73chjFcbMAOD9DdDq2tn1rp4rQa/K7O/zdnZpSYAT3nI33Q0aY6ts6t0PUVu5hCA==",
|
"contentHash": "xxYlTpcTEWsxaWUscDLN32mM32ysslLFtNQBS6wJOxaKJ9LCvusXDyBVEKL2DPbB8PZdereNvyrVr0deHkuOEw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Components": "8.0.3",
|
"Microsoft.AspNetCore.Components": "8.0.6",
|
||||||
"Microsoft.AspNetCore.Components.Forms": "8.0.3",
|
"Microsoft.AspNetCore.Components.Forms": "8.0.6",
|
||||||
"Microsoft.Extensions.DependencyInjection": "8.0.0",
|
"Microsoft.Extensions.DependencyInjection": "8.0.0",
|
||||||
"Microsoft.Extensions.Primitives": "8.0.0",
|
"Microsoft.Extensions.Primitives": "8.0.0",
|
||||||
"Microsoft.JSInterop": "8.0.3",
|
"Microsoft.JSInterop": "8.0.6",
|
||||||
"System.IO.Pipelines": "8.0.0"
|
"System.IO.Pipelines": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Metadata": {
|
"Microsoft.AspNetCore.Metadata": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "MAdmICjtSckGDutLRMydRI0pvBcGw/WoC4UC+hZ999idVW96l5iJlhyrtakgYkF5Rp0ekNVNWA+onP2gJZUkpw=="
|
"contentHash": "3e7S/kz1MGds8zDA8SfQiutqifyVcULs5P/8Bxpes0WIkJRMGkU/l+XlMllj9KrDfCGwHW8bgjRy/zxfoILgfg=="
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.DependencyInjection": {
|
"Microsoft.Extensions.DependencyInjection": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -116,19 +116,19 @@
|
|||||||
},
|
},
|
||||||
"Microsoft.Extensions.Localization": {
|
"Microsoft.Extensions.Localization": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "EjHnIiEwNq9xl8S36hf0nj64IF3DTQ1l5PVK8Vo+QocYKDKpDPONHNJC8env0DPwod7T5oA1HYLLo2mdSTCgrQ==",
|
"contentHash": "EXcSpQE6E80Qutej0ZShz1oRWBFocDzir/R3Gd1jAqZ5SnPpSr1Ep/tH5ha0cRXY22cWVuOb7I9rM32Ew+ju7g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1",
|
||||||
"Microsoft.Extensions.Localization.Abstractions": "8.0.3",
|
"Microsoft.Extensions.Localization.Abstractions": "8.0.6",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.1",
|
||||||
"Microsoft.Extensions.Options": "8.0.2"
|
"Microsoft.Extensions.Options": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Localization.Abstractions": {
|
"Microsoft.Extensions.Localization.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "k/kUPm1FQBxcs9/vsM1eF4qIOg2Sovqh/+KUGHur5Mc0Y3OFGuoz9ktBX7LA0gPz53SZhW3W3oaSaMFFcjgM6Q=="
|
"contentHash": "oQdKQ4xlb+Qa4t1gWGj58cocLdWZynP+wLExIAxozh2SrvffEzTvTGI2IbRx4mBNgg9jbbyoPE8nNOwJ1Thddg=="
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Abstractions": {
|
"Microsoft.Extensions.Logging.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -154,8 +154,8 @@
|
|||||||
},
|
},
|
||||||
"Microsoft.JSInterop": {
|
"Microsoft.JSInterop": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.3",
|
"resolved": "8.0.6",
|
||||||
"contentHash": "Oi21Fa7KubCzafwXb2IOdSGg24+/ylYGwrJgAYdWmgXBj04Oj/1b8vr9hrcoFKjQ6K18ryHYh35ZO/CCIEhuzg=="
|
"contentHash": "E1djWS3d41fcd++7sGlbYhOHde5Pb0oBpOcNvUbn+1ga/yCvsjzUfbd/tDRg1qacNKS0iwKWYOIqTZxJnh99dQ=="
|
||||||
},
|
},
|
||||||
"System.IO.Pipelines": {
|
"System.IO.Pipelines": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# v0.8.3, build 165 (2024-07-25 13:25 UTC)
|
||||||
|
- Added an option to configure the behavior of the navigation bar in the settings
|
||||||
|
- Added support for Fireworks.ai as provider, where you can use e.g., the llama 3.1 405b model
|
||||||
|
- Improved the handling of self-hosted provider hostnames
|
||||||
|
- Improved the configured provider table: long model names are now truncated
|
||||||
|
- Migrated UI framework from MudBlazor v6.x.x to v7.x.x
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# v0.8.4, build 166 (2024-07-26 06:53 UTC)
|
||||||
|
- Fixed issue #44: After upgrading to MudBlazor 7.x.x, text padding was off, and tooltips were not displayed correctly. This issue was shown only on releases, not on the development builds.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# v0.8.5, build 167 (2024-07-28 16:44 UTC)
|
||||||
|
- Added the possibility to provide default options for the icon finder assistant
|
||||||
|
- Added the possibility to provide default options for the translation assistant
|
||||||
|
- Added the possibility to provide default options for the coding assistant
|
||||||
|
- Added the possibility to provide default options for the text summarizer assistant
|
||||||
|
- Improved readability of the issue component
|
||||||
|
- Improved switches: when an option is enabled, the switch is using a different color
|
||||||
|
- Fixed the applying of spellchecking settings to the single-line dialog
|
||||||
|
- Fixed the bug where users cannot delete a self-hosted provider when an API token was never entered
|
||||||
|
- Fixed the bug where users were no longer able to move chats to workspaces, caused by the migration to MudBlazor 7.x.x
|
||||||
|
- Restructured the layout of the settings page
|
||||||
|
- Refactored the settings data model
|
||||||
|
- Upgraded to Rust 1.80.0
|
||||||
|
- Upgraded all Rust dependencies
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
* MudBlazor (https://mudblazor.com/)
|
* MudBlazor (https://mudblazor.com/)
|
||||||
* Copyright (c) 2021 MudBlazor
|
* Copyright (c) 2021 MudBlazor
|
||||||
* Licensed under MIT (https://github.com/MudBlazor/MudBlazor/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/MudBlazor/MudBlazor/blob/master/LICENSE)
|
||||||
*/.mud-primary{background-color:var(--mud-palette-primary) !important}.mud-primary-text{color:var(--mud-palette-primary) !important}.mud-primary-hover{background-color:var(--mud-palette-primary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-primary-hover:hover{background-color:var(--mud-palette-primary-hover) !important}}.hover\:mud-primary-hover:focus-visible,.hover\:mud-primary-hover:active{background-color:var(--mud-palette-primary-hover) !important}.mud-border-primary{border-color:var(--mud-palette-primary) !important}.mud-theme-primary{color:var(--mud-palette-primary-text) !important;background-color:var(--mud-palette-primary) !important}.mud-secondary{background-color:var(--mud-palette-secondary) !important}.mud-secondary-text{color:var(--mud-palette-secondary) !important}.mud-secondary-hover{background-color:var(--mud-palette-secondary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-secondary-hover:hover{background-color:var(--mud-palette-secondary-hover) !important}}.hover\:mud-secondary-hover:focus-visible,.hover\:mud-secondary-hover:active{background-color:var(--mud-palette-secondary-hover) !important}.mud-border-secondary{border-color:var(--mud-palette-secondary) !important}.mud-theme-secondary{color:var(--mud-palette-secondary-text) !important;background-color:var(--mud-palette-secondary) !important}.mud-tertiary{background-color:var(--mud-palette-tertiary) !important}.mud-tertiary-text{color:var(--mud-palette-tertiary) !important}.mud-tertiary-hover{background-color:var(--mud-palette-tertiary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-tertiary-hover:hover{background-color:var(--mud-palette-tertiary-hover) !important}}.hover\:mud-tertiary-hover:focus-visible,.hover\:mud-tertiary-hover:active{background-color:var(--mud-palette-tertiary-hover) !important}.mud-border-tertiary{border-color:var(--mud-palette-tertiary) !important}.mud-theme-tertiary{color:var(--mud-palette-tertiary-text) !important;background-color:var(--mud-palette-tertiary) !important}.mud-info{background-color:var(--mud-palette-info) !important}.mud-info-text{color:var(--mud-palette-info) !important}.mud-info-hover{background-color:var(--mud-palette-info-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-info-hover:hover{background-color:var(--mud-palette-info-hover) !important}}.hover\:mud-info-hover:focus-visible,.hover\:mud-info-hover:active{background-color:var(--mud-palette-info-hover) !important}.mud-border-info{border-color:var(--mud-palette-info) !important}.mud-theme-info{color:var(--mud-palette-info-text) !important;background-color:var(--mud-palette-info) !important}.mud-success{background-color:var(--mud-palette-success) !important}.mud-success-text{color:var(--mud-palette-success) !important}.mud-success-hover{background-color:var(--mud-palette-success-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-success-hover:hover{background-color:var(--mud-palette-success-hover) !important}}.hover\:mud-success-hover:focus-visible,.hover\:mud-success-hover:active{background-color:var(--mud-palette-success-hover) !important}.mud-border-success{border-color:var(--mud-palette-success) !important}.mud-theme-success{color:var(--mud-palette-success-text) !important;background-color:var(--mud-palette-success) !important}.mud-warning{background-color:var(--mud-palette-warning) !important}.mud-warning-text{color:var(--mud-palette-warning) !important}.mud-warning-hover{background-color:var(--mud-palette-warning-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-warning-hover:hover{background-color:var(--mud-palette-warning-hover) !important}}.hover\:mud-warning-hover:focus-visible,.hover\:mud-warning-hover:active{background-color:var(--mud-palette-warning-hover) !important}.mud-border-warning{border-color:var(--mud-palette-warning) !important}.mud-theme-warning{color:var(--mud-palette-warning-text) !important;background-color:var(--mud-palette-warning) !important}.mud-error{background-color:var(--mud-palette-error) !important}.mud-error-text{color:var(--mud-palette-error) !important}.mud-error-hover{background-color:var(--mud-palette-error-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-error-hover:hover{background-color:var(--mud-palette-error-hover) !important}}.hover\:mud-error-hover:focus-visible,.hover\:mud-error-hover:active{background-color:var(--mud-palette-error-hover) !important}.mud-border-error{border-color:var(--mud-palette-error) !important}.mud-theme-error{color:var(--mud-palette-error-text) !important;background-color:var(--mud-palette-error) !important}.mud-dark{background-color:var(--mud-palette-dark) !important}.mud-dark-text{color:var(--mud-palette-dark) !important}.mud-dark-hover{background-color:var(--mud-palette-dark-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-dark-hover:hover{background-color:var(--mud-palette-dark-hover) !important}}.hovLine truncated
|
*/.mud-primary{background-color:var(--mud-palette-primary) !important}.mud-primary-text{color:var(--mud-palette-primary) !important;--mud-ripple-color: var(--mud-palette-primary) !important}.mud-primary-hover{background-color:var(--mud-palette-primary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-primary-hover:hover{background-color:var(--mud-palette-primary-hover) !important}}.hover\:mud-primary-hover:focus-visible,.hover\:mud-primary-hover:active{background-color:var(--mud-palette-primary-hover) !important}.mud-border-primary{border-color:var(--mud-palette-primary) !important}.mud-theme-primary{color:var(--mud-palette-primary-text) !important;background-color:var(--mud-palette-primary) !important}.mud-secondary{background-color:var(--mud-palette-secondary) !important}.mud-secondary-text{color:var(--mud-palette-secondary) !important;--mud-ripple-color: var(--mud-palette-secondary) !important}.mud-secondary-hover{background-color:var(--mud-palette-secondary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-secondary-hover:hover{background-color:var(--mud-palette-secondary-hover) !important}}.hover\:mud-secondary-hover:focus-visible,.hover\:mud-secondary-hover:active{background-color:var(--mud-palette-secondary-hover) !important}.mud-border-secondary{border-color:var(--mud-palette-secondary) !important}.mud-theme-secondary{color:var(--mud-palette-secondary-text) !important;background-color:var(--mud-palette-secondary) !important}.mud-tertiary{background-color:var(--mud-palette-tertiary) !important}.mud-tertiary-text{color:var(--mud-palette-tertiary) !important;--mud-ripple-color: var(--mud-palette-tertiary) !important}.mud-tertiary-hover{background-color:var(--mud-palette-tertiary-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-tertiary-hover:hover{background-color:var(--mud-palette-tertiary-hover) !important}}.hover\:mud-tertiary-hover:focus-visible,.hover\:mud-tertiary-hover:active{background-color:var(--mud-palette-tertiary-hover) !important}.mud-border-tertiary{border-color:var(--mud-palette-tertiary) !important}.mud-theme-tertiary{color:var(--mud-palette-tertiary-text) !important;background-color:var(--mud-palette-tertiary) !important}.mud-info{background-color:var(--mud-palette-info) !important}.mud-info-text{color:var(--mud-palette-info) !important;--mud-ripple-color: var(--mud-palette-info) !important}.mud-info-hover{background-color:var(--mud-palette-info-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-info-hover:hover{background-color:var(--mud-palette-info-hover) !important}}.hover\:mud-info-hover:focus-visible,.hover\:mud-info-hover:active{background-color:var(--mud-palette-info-hover) !important}.mud-border-info{border-color:var(--mud-palette-info) !important}.mud-theme-info{color:var(--mud-palette-info-text) !important;background-color:var(--mud-palette-info) !important}.mud-success{background-color:var(--mud-palette-success) !important}.mud-success-text{color:var(--mud-palette-success) !important;--mud-ripple-color: var(--mud-palette-success) !important}.mud-success-hover{background-color:var(--mud-palette-success-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-success-hover:hover{background-color:var(--mud-palette-success-hover) !important}}.hover\:mud-success-hover:focus-visible,.hover\:mud-success-hover:active{background-color:var(--mud-palette-success-hover) !important}.mud-border-success{border-color:var(--mud-palette-success) !important}.mud-theme-success{color:var(--mud-palette-success-text) !important;background-color:var(--mud-palette-success) !important}.mud-warning{background-color:var(--mud-palette-warning) !important}.mud-warning-text{color:var(--mud-palette-warning) !important;--mud-ripple-color: var(--mud-palette-warning) !important}.mud-warning-hover{background-color:var(--mud-palette-warning-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-warning-hover:hover{background-color:var(--mud-palette-warning-hover) !important}}.hover\:mud-warning-hover:focus-visible,.hover\:mud-warning-hover:active{background-color:var(--mud-palette-warning-hover) !important}.mud-border-warning{border-color:var(--mud-palette-warning) !important}.mud-theme-warning{color:var(--mud-palette-warning-text) !important;background-color:var(--mud-palette-warning) !important}.mud-error{background-color:var(--mud-palette-error) !important}.mud-error-text{color:var(--mud-palette-error) !important;--mud-ripple-color: var(--mud-palette-error) !important}.mud-error-hover{background-color:var(--mud-palette-error-hover) !important}@media(hover: hover)and (pointer: fine){.hover\:mud-error-hover:hover{background-color:var(--mud-palette-error-hover) !important}}.hover\:mud-error-hover:focus-visible,.hover\:mud-error-hover:active{background-color:var(--mud-palette-error-hover) !important}.mud-border-error{border-color:var(--mud-palette-error) !important}.mud-theme-error{color:var(--mud-paleLine truncated
|
||||||
+172
-163
@@ -1,11 +1,28 @@
|
|||||||
|
|
||||||
window.mudDragAndDrop={initDropZone:(id)=>{const elem=document.getElementById('mud-drop-zone-'+id);elem.addEventListener('dragover',()=>event.preventDefault());elem.addEventListener('dragstart',()=>event.dataTransfer.setData('',event.target.id));},makeDropZonesNotRelative:()=>{var firstDropItems=Array.from(document.getElementsByClassName('mud-drop-item')).filter(x=>x.getAttribute('index')=="-1");for(let dropItem of firstDropItems){dropItem.style.position='static';}
|
window.getTabbableElements=(element)=>{return element.querySelectorAll("a[href]:not([tabindex='-1']),"+"area[href]:not([tabindex='-1']),"+"button:not([disabled]):not([tabindex='-1']),"+"input:not([disabled]):not([tabindex='-1']):not([type='hidden']),"+"select:not([disabled]):not([tabindex='-1']),"+"textarea:not([disabled]):not([tabindex='-1']),"+"iframe:not([tabindex='-1']),"+"details:not([tabindex='-1']),"+"[tabindex]:not([tabindex='-1']),"+"[contentEditable=true]:not([tabindex='-1'])");};window.serializeParameter=(data,spec)=>{if(typeof data=="undefined"||data===null){return null;}
|
||||||
const dropZones=document.getElementsByClassName('mud-drop-zone');for(let dropZone of dropZones){dropZone.style.position='unset';}},getDropZoneIdentifierOnPosition:(x,y)=>{const elems=document.elementsFromPoint(x,y);const dropZones=elems.filter(e=>e.classList.contains('mud-drop-zone'))
|
if(typeof data==="number"||typeof data==="string"||typeof data=="boolean"){return data;}
|
||||||
const dropZone=dropZones[0];if(dropZone){return dropZone.getAttribute('identifier')||"";}
|
let res=(Array.isArray(data))?[]:{};if(!spec){spec="*";}
|
||||||
return"";},getDropIndexOnPosition:(x,y,id)=>{const elems=document.elementsFromPoint(x,y);const dropItems=elems.filter(e=>e.classList.contains('mud-drop-item')&&e.id!=('mud-drop-item-'+id))
|
for(let i in data){let currentMember=data[i];if(typeof currentMember==='function'||currentMember===null){continue;}
|
||||||
const dropItem=dropItems[0];if(dropItem){return dropItem.getAttribute('index')||"";}
|
let currentMemberSpec;if(spec!="*"){currentMemberSpec=Array.isArray(data)?spec:spec[i];if(!currentMemberSpec){continue;}}else{currentMemberSpec="*"}
|
||||||
return"";},makeDropZonesRelative:()=>{const dropZones=document.getElementsByClassName('mud-drop-zone');for(let dropZone of dropZones){dropZone.style.position='relative';}
|
if(typeof currentMember==='object'){if(Array.isArray(currentMember)||currentMember.length){res[i]=[];for(let j=0;j<currentMember.length;j++){const arrayItem=currentMember[j];if(typeof arrayItem==='object'){res[i].push(this.serializeParameter(arrayItem,currentMemberSpec));}else{res[i].push(arrayItem);}}}else{if(currentMember.length===0){res[i]=[];}else{res[i]=this.serializeParameter(currentMember,currentMemberSpec);}}}else{if(currentMember===Infinity){currentMember="Infinity";}
|
||||||
var firstDropItems=Array.from(document.getElementsByClassName('mud-drop-item')).filter(x=>x.getAttribute('index')=="-1");for(let dropItem of firstDropItems){dropItem.style.position='relative';}},moveItemByDifference:(id,dx,dy)=>{const elem=document.getElementById('mud-drop-item-'+id);var tx=(parseFloat(elem.getAttribute('data-x'))||0)+dx;var ty=(parseFloat(elem.getAttribute('data-y'))||0)+dy;elem.style.webkitTransform=elem.style.transform='translate3d('+tx+'px, '+ty+'px, 10px)';elem.setAttribute('data-x',tx);elem.setAttribute('data-y',ty);},resetItem:(id)=>{const elem=document.getElementById('mud-drop-item-'+id);if(elem){elem.style.webkitTransform=elem.style.transform='';elem.setAttribute('data-x',0);elem.setAttribute('data-y',0);}}};class MudKeyInterceptorFactory{connect(dotNetRef,elementId,options){if(!elementId)
|
if(currentMember!==null){res[i]=currentMember;}}}
|
||||||
|
return res;};class MudResizeObserverFactory{constructor(){this._maps={};}
|
||||||
|
connect(id,dotNetRef,elements,elementIds,options){var existingEntry=this._maps[id];if(!existingEntry){var observer=new MudResizeObserver(dotNetRef,options);this._maps[id]=observer;}
|
||||||
|
var result=this._maps[id].connect(elements,elementIds);return result;}
|
||||||
|
disconnect(id,element){var existingEntry=this._maps[id];if(existingEntry){existingEntry.disconnect(element);}}
|
||||||
|
cancelListener(id){var existingEntry=this._maps[id];if(existingEntry){existingEntry.cancelListener();delete this._maps[id];}}}
|
||||||
|
class MudResizeObserver{constructor(dotNetRef,options){this.logger=options.enableLogging?console.log:(message)=>{};this.options=options;this._dotNetRef=dotNetRef
|
||||||
|
var delay=(this.options||{}).reportRate||200;this.throttleResizeHandlerId=-1;var observervedElements=[];this._observervedElements=observervedElements;this.logger('[MudBlazor | ResizeObserver] Observer initialized');this._resizeObserver=new ResizeObserver(entries=>{var changes=[];this.logger('[MudBlazor | ResizeObserver] changes detected');for(let entry of entries){var target=entry.target;var affectedObservedElement=observervedElements.find((x)=>x.element==target);if(affectedObservedElement){var size=entry.target.getBoundingClientRect();if(affectedObservedElement.isInitialized==true){changes.push({id:affectedObservedElement.id,size:size});}
|
||||||
|
else{affectedObservedElement.isInitialized=true;}}}
|
||||||
|
if(changes.length>0){if(this.throttleResizeHandlerId>=0){clearTimeout(this.throttleResizeHandlerId);}
|
||||||
|
this.throttleResizeHandlerId=window.setTimeout(this.resizeHandler.bind(this,changes),delay);}});}
|
||||||
|
resizeHandler(changes){try{this.logger("[MudBlazor | ResizeObserver] OnSizeChanged handler invoked");this._dotNetRef.invokeMethodAsync("OnSizeChanged",changes);}catch(error){this.logger("[MudBlazor | ResizeObserver] Error in OnSizeChanged handler:",{error});}}
|
||||||
|
connect(elements,ids){var result=[];this.logger('[MudBlazor | ResizeObserver] Start observing elements...');for(var i=0;i<elements.length;i++){var newEntry={element:elements[i],id:ids[i],isInitialized:false,};this.logger("[MudBlazor | ResizeObserver] Start observing element:",{newEntry});result.push(elements[i].getBoundingClientRect());this._observervedElements.push(newEntry);this._resizeObserver.observe(elements[i]);}
|
||||||
|
return result;}
|
||||||
|
disconnect(elementId){this.logger('[MudBlazor | ResizeObserver] Try to unobserve element with id',{elementId});var affectedObservedElement=this._observervedElements.find((x)=>x.id==elementId);if(affectedObservedElement){var element=affectedObservedElement.element;this._resizeObserver.unobserve(element);this.logger('[MudBlazor | ResizeObserver] Element found. Ubobserving size changes of element',{element});var index=this._observervedElements.indexOf(affectedObservedElement);this._observervedElements.splice(index,1);}}
|
||||||
|
cancelListener(){this.logger('[MudBlazor | ResizeObserver] Closing ResizeObserver. Detaching all observed elements');this._resizeObserver.disconnect();this._dotNetRef=undefined;}}
|
||||||
|
window.mudResizeObserver=new MudResizeObserverFactory();class MudInput{resetValue(id){const input=document.getElementById(id);if(input){input.value='';}}}
|
||||||
|
window.mudInput=new MudInput();class MudKeyInterceptorFactory{connect(dotNetRef,elementId,options){if(!elementId)
|
||||||
throw"elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
throw"elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
||||||
throw"no element found for id: "+elementId;if(!element.mudKeyInterceptor)
|
throw"no element found for id: "+elementId;if(!element.mudKeyInterceptor)
|
||||||
element.mudKeyInterceptor=new MudKeyInterceptor(dotNetRef,options);element.mudKeyInterceptor.connect(element);}
|
element.mudKeyInterceptor=new MudKeyInterceptor(dotNetRef,options);element.mudKeyInterceptor.connect(element);}
|
||||||
@@ -59,69 +76,86 @@ processKeyUp(args,keyOptions){if(this.matchesKeyCombination(keyOptions.preventUp
|
|||||||
args.preventDefault();if(this.matchesKeyCombination(keyOptions.stopUp,args))
|
args.preventDefault();if(this.matchesKeyCombination(keyOptions.stopUp,args))
|
||||||
args.stopPropagation();}
|
args.stopPropagation();}
|
||||||
toKeyboardEventArgs(args){return{Key:args.key,Code:args.code,Location:args.location,Repeat:args.repeat,CtrlKey:args.ctrlKey,ShiftKey:args.shiftKey,AltKey:args.altKey,MetaKey:args.metaKey};}}
|
toKeyboardEventArgs(args){return{Key:args.key,Code:args.code,Location:args.location,Repeat:args.repeat,CtrlKey:args.ctrlKey,ShiftKey:args.shiftKey,AltKey:args.altKey,MetaKey:args.metaKey};}}
|
||||||
class MudThrottledEventManager{constructor(){this.mapper={};}
|
class MudElementReference{constructor(){this.listenerId=0;this.eventListeners={};}
|
||||||
subscribe(eventName,elementId,projection,throotleInterval,key,properties,dotnetReference){const handlerRef=this.throttleEventHandler.bind(this,key);let elem=document.getElementById(elementId);if(elem){elem.addEventListener(eventName,handlerRef,false);let projector=null;if(projection){const parts=projection.split('.');let functionPointer=window;let functionReferenceFound=true;if(parts.length==0||parts.length==1){functionPointer=functionPointer[projection];}
|
focus(element){if(element)
|
||||||
else{for(let i=0;i<parts.length;i++){functionPointer=functionPointer[parts[i]];if(!functionPointer){functionReferenceFound=false;break;}}}
|
{element.focus();}}
|
||||||
if(functionReferenceFound===true){projector=functionPointer;}}
|
blur(element){if(element){element.blur();}}
|
||||||
this.mapper[key]={eventName:eventName,handler:handlerRef,delay:throotleInterval,timerId:-1,reference:dotnetReference,elementId:elementId,properties:properties,projection:projector,};}}
|
focusFirst(element,skip=0,min=0){if(element)
|
||||||
subscribeGlobal(eventName,throotleInterval,key,properties,dotnetReference){let handlerRef=throotleInterval>0?this.throttleEventHandler.bind(this,key):this.eventHandler.bind(this,key);document.addEventListener(eventName,handlerRef,false);this.mapper[key]={eventName:eventName,handler:handlerRef,delay:throotleInterval,timerId:-1,reference:dotnetReference,elementId:document,properties:properties,projection:null,};}
|
{let tabbables=getTabbableElements(element);if(tabbables.length<=min)
|
||||||
throttleEventHandler(key,event){const entry=this.mapper[key];if(!entry){return;}
|
element.focus();else
|
||||||
clearTimeout(entry.timerId);entry.timerId=window.setTimeout(this.eventHandler.bind(this,key,event),entry.delay);}
|
tabbables[skip].focus();}}
|
||||||
eventHandler(key,event){const entry=this.mapper[key];if(!entry){return;}
|
focusLast(element,skip=0,min=0){if(element)
|
||||||
var elem=document.getElementById(entry.elementId);if(elem!=event.srcElement&&entry.elementId!=document){return;}
|
{let tabbables=getTabbableElements(element);if(tabbables.length<=min)
|
||||||
const eventEntry={};for(var i=0;i<entry.properties.length;i++){eventEntry[entry.properties[i]]=event[entry.properties[i]];}
|
element.focus();else
|
||||||
if(entry.projection){if(typeof entry.projection==="function"){entry.projection.apply(null,[eventEntry,event]);}}
|
tabbables[tabbables.length-skip-1].focus();}}
|
||||||
entry.reference.invokeMethodAsync('OnEventOccur',key,JSON.stringify(eventEntry));}
|
saveFocus(element){if(element)
|
||||||
unsubscribe(key){const entry=this.mapper[key];if(!entry){return;}
|
{element['mudblazor_savedFocus']=document.activeElement;}}
|
||||||
entry.reference=null;if(document==entry.elementId){document.removeEventListener(entry.eventName,entry.handler,false);}else{const elem=document.getElementById(entry.elementId);if(elem){elem.removeEventListener(entry.eventName,entry.handler,false);}}
|
restoreFocus(element){if(element)
|
||||||
delete this.mapper[key];}};window.mudThrottledEventManager=new MudThrottledEventManager();window.mudEventProjections={correctOffset:function(eventEntry,event){var target=event.target.getBoundingClientRect();eventEntry.offsetX=event.clientX-target.x;eventEntry.offsetY=event.clientY-target.y;}};class MudJsEventFactory{connect(dotNetRef,elementId,options){if(!elementId)
|
{let previous=element['mudblazor_savedFocus'];delete element['mudblazor_savedFocus']
|
||||||
throw"[MudBlazor | JsEvent] elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
if(previous)
|
||||||
throw"[MudBlazor | JsEvent] no element found for id: "+elementId;if(!element.mudJsEvent)
|
previous.focus();}}
|
||||||
element.mudJsEvent=new MudJsEvent(dotNetRef,options);element.mudJsEvent.connect(element);}
|
selectRange(element,pos1,pos2){if(element)
|
||||||
disconnect(elementId){var element=document.getElementById(elementId);if(!element||!element.mudJsEvent)
|
{if(element.createTextRange){let selRange=element.createTextRange();selRange.collapse(true);selRange.moveStart('character',pos1);selRange.moveEnd('character',pos2);selRange.select();}else if(element.setSelectionRange){element.setSelectionRange(pos1,pos2);}else if(element.selectionStart){element.selectionStart=pos1;element.selectionEnd=pos2;}
|
||||||
return;element.mudJsEvent.disconnect();}
|
element.focus();}}
|
||||||
subscribe(elementId,eventName){if(!elementId)
|
select(element){if(element)
|
||||||
throw"[MudBlazor | JsEvent] elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
{element.select();}}
|
||||||
throw"[MudBlazor | JsEvent] no element found for id: "+elementId;if(!element.mudJsEvent)
|
getBoundingClientRect(element){if(!element)return;var rect=JSON.parse(JSON.stringify(element.getBoundingClientRect()));rect.scrollY=window.scrollY||document.documentElement.scrollTop;rect.scrollX=window.scrollX||document.documentElement.scrollLeft;rect.windowHeight=window.innerHeight;rect.windowWidth=window.innerWidth;return rect;}
|
||||||
throw"[MudBlazor | JsEvent] please connect before subscribing"
|
changeCss(element,css){if(element)
|
||||||
element.mudJsEvent.subscribe(eventName);}
|
{element.className=css;}}
|
||||||
unsubscribe(elementId,eventName){var element=document.getElementById(elementId);if(!element||!element.mudJsEvent)
|
removeEventListener(element,event,eventId){element.removeEventListener(event,this.eventListeners[eventId]);delete this.eventListeners[eventId];}
|
||||||
return;element.mudJsEvent.unsubscribe(element,eventName);}}
|
addDefaultPreventingHandler(element,eventName){let listener=function(e){e.preventDefault();}
|
||||||
window.mudJsEvent=new MudJsEventFactory();class MudJsEvent{constructor(dotNetRef,options){this._dotNetRef=dotNetRef;this._options=options||{};this.logger=options.enableLogging?console.log:(message)=>{};this.logger('[MudBlazor | JsEvent] Initialized',{options});this._subscribedEvents={};}
|
element.addEventListener(eventName,listener,{passive:false});this.eventListeners[++this.listenerId]=listener;return this.listenerId;}
|
||||||
connect(element){if(!this._options)
|
removeDefaultPreventingHandler(element,eventName,listenerId){this.removeEventListener(element,eventName,listenerId);}
|
||||||
return;if(!this._options.targetClass)
|
addDefaultPreventingHandlers(element,eventNames){let listeners=[];for(const eventName of eventNames){let listenerId=this.addDefaultPreventingHandler(element,eventName);listeners.push(listenerId);}
|
||||||
throw"_options.targetClass: css class name expected";if(this._observer){return;}
|
return listeners;}
|
||||||
var targetClass=this._options.targetClass;this.logger('[MudBlazor | JsEvent] Start observing DOM of element for changes to child with class ',{element,targetClass});this._element=element;this._observer=new MutationObserver(this.onDomChanged);this._observer.mudJsEvent=this;this._observer.observe(this._element,{attributes:false,childList:true,subtree:true});this._observedChildren=[];}
|
removeDefaultPreventingHandlers(element,eventNames,listenerIds){for(let index=0;index<eventNames.length;++index){const eventName=eventNames[index];const listenerId=listenerIds[index];this.removeDefaultPreventingHandler(element,eventName,listenerId);}}};window.mudElementRef=new MudElementReference();const darkThemeMediaQuery=window.matchMedia("(prefers-color-scheme: dark)");window.darkModeChange=()=>{return darkThemeMediaQuery.matches;};function darkModeChangeListener(e){dotNetHelperTheme.invokeMethodAsync('SystemPreferenceChanged',e.matches);}
|
||||||
disconnect(){if(!this._observer)
|
function watchDarkThemeMedia(dotNetHelper){dotNetHelperTheme=dotNetHelper;darkThemeMediaQuery.addEventListener('change',darkModeChangeListener);}
|
||||||
return;this.logger('[MudBlazor | JsEvent] disconnect mutation observer and event handler ');this._observer.disconnect();this._observer=null;for(const child of this._observedChildren)
|
function stopWatchingDarkThemeMedia(){darkThemeMediaQuery.removeEventListener('change',darkModeChangeListener);}
|
||||||
this.detachHandlers(child);}
|
class MudScrollSpy{constructor(){this.lastKnowElement=null;this.handlerRef=null;}
|
||||||
subscribe(eventName){if(this._subscribedEvents[eventName]){return;}
|
spying(dotnetReference,containerSelector,sectionClassSelector){this.lastKnowElement=null;this.handlerRef=this.handleScroll.bind(this,dotnetReference,containerSelector,sectionClassSelector);document.addEventListener('scroll',this.handlerRef,true);window.addEventListener('resize',this.handlerRef,true);}
|
||||||
var element=this._element;var targetClass=this._options.targetClass;this._subscribedEvents[eventName]=true;for(const child of element.getElementsByClassName(targetClass)){this.attachHandlers(child);}}
|
handleScroll(dotnetReference,containerSelector,sectionClassSelector,event){const container=document.querySelector(containerSelector);if(container===null){return;}
|
||||||
unsubscribe(eventName){if(!this._observer)
|
const elements=document.getElementsByClassName(sectionClassSelector);if(elements.length===0){return;}
|
||||||
return;this.logger('[MudBlazor | JsEvent] unsubscribe event handler '+eventName);this._observer.disconnect();this._observer=null;this._subscribedEvents[eventName]=false;for(const child of this._observedChildren){this.detachHandler(child,eventName);}}
|
const containerTop=container.tagName==='HTML'?0:container.getBoundingClientRect().top;const containerHeight=container.clientHeight;const center=containerTop+containerHeight/2.0;let minDifference=Number.MAX_SAFE_INTEGER;let foundAbove=false;let elementId='';for(let i=0;i<elements.length;i++){const element=elements[i];const rect=element.getBoundingClientRect();const diff=Math.abs(rect.top-center);if(!foundAbove&&rect.top<center){foundAbove=true;minDifference=diff;elementId=element.id;continue;}
|
||||||
attachHandlers(child){child.mudJsEvent=this;for(var eventName of Object.getOwnPropertyNames(this._subscribedEvents)){if(!this._subscribedEvents[eventName])
|
if(foundAbove&&rect.top>=center){continue;}
|
||||||
continue;this.logger('[MudBlazor | JsEvent] attaching event '+eventName,child);child.addEventListener(eventName,this.eventHandler);}
|
if(diff<minDifference){minDifference=diff;elementId=element.id;}}
|
||||||
if(this._observedChildren.indexOf(child)<0)
|
if(elementId!==this.lastKnowElement){this.lastKnowElement=elementId;history.replaceState(null,'',window.location.pathname+"#"+elementId);dotnetReference.invokeMethodAsync('SectionChangeOccured',elementId);}}
|
||||||
this._observedChildren.push(child);}
|
activateSection(sectionId){const element=document.getElementById(sectionId);if(element){this.lastKnowElement=sectionId;history.replaceState(null,'',window.location.pathname+"#"+sectionId);}}
|
||||||
detachHandler(child,eventName){this.logger('[MudBlazor | JsEvent] detaching handler '+eventName,child);child.removeEventListener(eventName,this.eventHandler);}
|
scrollToSection(sectionId){if(sectionId){let element=document.getElementById(sectionId);if(element){element.scrollIntoView({behavior:'smooth',block:'center',inline:'start'});}}
|
||||||
detachHandlers(child){this.logger('[MudBlazor | JsEvent] detaching handlers ',child);for(var eventName of Object.getOwnPropertyNames(this._subscribedEvents)){if(!this._subscribedEvents[eventName])
|
else{window.scrollTo({top:0,behavior:'smooth'});}}
|
||||||
continue;child.removeEventListener(eventName,this.eventHandler);}
|
unspy(){document.removeEventListener('scroll',this.handlerRef,true);window.removeEventListener('resize',this.handlerRef,true);}};window.mudScrollSpy=new MudScrollSpy();window.mudInputAutoGrow={initAutoGrow:(elem,maxLines)=>{const compStyle=getComputedStyle(elem);const lineHeight=parseFloat(compStyle.getPropertyValue('line-height'));let maxHeight=0;elem.updateParameters=function(newMaxLines){if(newMaxLines>0){maxHeight=lineHeight*newMaxLines;}else{maxHeight=0;}}
|
||||||
this._observedChildren=this._observedChildren.filter(x=>x!==child);}
|
elem.adjustAutoGrowHeight=function(didReflow=false){const scrollTops=[];let curElem=elem;while(curElem&&curElem.parentNode&&curElem.parentNode instanceof Element){if(curElem.parentNode.scrollTop){scrollTops.push([curElem.parentNode,curElem.parentNode.scrollTop]);}
|
||||||
onDomChanged(mutationsList,observer){var self=this.mudJsEvent;var targetClass=self._options.targetClass;for(const mutation of mutationsList){for(const element of mutation.addedNodes){if(element.classList&&element.classList.contains(targetClass)){if(!self._options.TagName||element.tagName==self._options.TagName)
|
curElem=curElem.parentNode;}
|
||||||
self.attachHandlers(element);}}
|
elem.style.height=0;if(didReflow){elem.style.textAlign=null;}
|
||||||
for(const element of mutation.removedNodes){if(element.classList&&element.classList.contains(targetClass)){if(!self._options.tagName||element.tagName==self._options.tagName)
|
let minHeight=lineHeight*elem.rows;let newHeight=Math.max(minHeight,elem.scrollHeight);let initialOverflowY=elem.style.overflowY;if(maxHeight>0&&newHeight>maxHeight){elem.style.overflowY='auto';newHeight=maxHeight;}else{elem.style.overflowY='hidden';}
|
||||||
self.detachHandlers(element);}}}}
|
elem.style.height=newHeight+"px";scrollTops.forEach(([node,scrollTop])=>{node.style.scrollBehavior='auto';node.scrollTop=scrollTop;node.style.scrollBehavior=null;});if(!didReflow&&initialOverflowY!==elem.style.overflowY&&elem.style.overflowY==='hidden'){elem.style.textAlign='end';elem.adjustAutoGrowHeight(true);}}
|
||||||
eventHandler(e){var self=this.mudJsEvent;var eventName=e.type;self.logger('[MudBlazor | JsEvent] "'+eventName+'"',e);self["on"+eventName](self,e);}
|
elem.restoreToInitialState=function(){elem.removeEventListener('input',elem.adjustAutoGrowHeight);elem.style.overflowY=null;elem.style.height=null;}
|
||||||
onkeyup(self,e){const caretPosition=e.target.selectionStart;const invoke=self._subscribedEvents["keyup"];if(invoke){self._dotNetRef.invokeMethodAsync('OnCaretPositionChanged',caretPosition);}}
|
elem.addEventListener('input',elem.adjustAutoGrowHeight);window.addEventListener('resize',elem.adjustAutoGrowHeight);elem.updateParameters(maxLines);elem.adjustAutoGrowHeight();},adjustHeight:(elem)=>{if(typeof elem.adjustAutoGrowHeight==='function'){elem.adjustAutoGrowHeight();}},updateParams:(elem,maxLines)=>{if(typeof elem.updateParameters==='function'){elem.updateParameters(maxLines);}
|
||||||
onclick(self,e){const caretPosition=e.target.selectionStart;const invoke=self._subscribedEvents["click"];if(invoke){self._dotNetRef.invokeMethodAsync('OnCaretPositionChanged',caretPosition);}}
|
if(typeof elem.adjustAutoGrowHeight==='function'){elem.adjustAutoGrowHeight();}},destroy:(elem)=>{window.removeEventListener('resize',elem.adjustAutoGrowHeight);if(typeof elem.restoreToInitialState==='function'){elem.restoreToInitialState();}}}
|
||||||
onpaste(self,e){const invoke=self._subscribedEvents["paste"];if(invoke){e.preventDefault();e.stopPropagation();const text=(e.originalEvent||e).clipboardData.getData('text/plain');self._dotNetRef.invokeMethodAsync('OnPaste',text);}}
|
window.mudTimePicker={initPointerEvents:(clock,dotNetHelper)=>{let isPointerDown=false;const startHandler=(event)=>{if(event.button!==0){return;}
|
||||||
onselect(self,e){const invoke=self._subscribedEvents["select"];if(invoke){const start=e.target.selectionStart;const end=e.target.selectionEnd;if(start===end)
|
isPointerDown=true;event.target.releasePointerCapture(event.pointerId);if(event.target.classList.contains('mud-hour')||event.target.classList.contains('mud-minute')){let attributeValue=event.target.getAttribute('data-stick-value');let stickValue=attributeValue?parseInt(attributeValue):-1;dotNetHelper.invokeMethodAsync('SelectTimeFromStick',stickValue,false);}
|
||||||
return;self._dotNetRef.invokeMethodAsync('OnSelect',start,end);}}}
|
event.preventDefault();};const endHandler=(event)=>{if(event.button!==0){return;}
|
||||||
class MudResizeListener{constructor(id){this.logger=function(message){};this.options={};this.throttleResizeHandlerId=-1;this.dotnet=undefined;this.breakpoint=-1;this.id=id;this.handleResize=this.throttleResizeHandler.bind(this);}
|
isPointerDown=false;if(event.target.classList.contains('mud-hour')||event.target.classList.contains('mud-minute')){let attributeValue=event.target.getAttribute('data-stick-value');let stickValue=attributeValue?parseInt(attributeValue):-1;dotNetHelper.invokeMethodAsync('OnStickClick',stickValue);}
|
||||||
|
event.preventDefault();};const moveHandler=(event)=>{if(!isPointerDown||(!event.target.classList.contains('mud-hour')&&!event.target.classList.contains('mud-minute'))){return;}
|
||||||
|
let attributeValue=event.target.getAttribute('data-stick-value');let stickValue=attributeValue?parseInt(attributeValue):-1;dotNetHelper.invokeMethodAsync('SelectTimeFromStick',stickValue,true);event.preventDefault();};clock.addEventListener('pointerdown',startHandler);clock.addEventListener('pointerup',endHandler);clock.addEventListener('pointercancel',endHandler);clock.addEventListener('pointerover',moveHandler);clock.destroy=()=>{clock.removeEventListener('pointerdown',startHandler);clock.removeEventListener('pointerup',endHandler);clock.removeEventListener('pointercancel',endHandler);clock.removeEventListener('pointerover',moveHandler);};},destroyPointerEvents:(container)=>{if(typeof container.destroy==='function'){container.destroy();}}};class MudScrollListener{constructor(){this.throttleScrollHandlerId=-1;this.handlerRef=null;}
|
||||||
|
listenForScroll(dotnetReference,selector){let element=selector?document.querySelector(selector):document;this.handlerRef=this.throttleScrollHandler.bind(this,dotnetReference);element.addEventListener('scroll',this.handlerRef,false);}
|
||||||
|
throttleScrollHandler(dotnetReference,event){clearTimeout(this.throttleScrollHandlerId);this.throttleScrollHandlerId=window.setTimeout(this.scrollHandler.bind(this,dotnetReference,event),100);}
|
||||||
|
scrollHandler(dotnetReference,event){try{let element=event.target;let scrollTop=element.scrollTop;let scrollHeight=element.scrollHeight;let scrollWidth=element.scrollWidth;let scrollLeft=element.scrollLeft;let nodeName=element.nodeName;let firstChild=element.firstElementChild;let firstChildBoundingClientRect=firstChild.getBoundingClientRect();dotnetReference.invokeMethodAsync('RaiseOnScroll',{firstChildBoundingClientRect,scrollLeft,scrollTop,scrollHeight,scrollWidth,nodeName,});}catch(error){console.log('[MudBlazor] Error in scrollHandler:',{error});}}
|
||||||
|
cancelListener(selector){let element=selector?document.querySelector(selector):document;element.removeEventListener('scroll',this.handlerRef);}};window.mudScrollListener=new MudScrollListener();window.mudDragAndDrop={initDropZone:(id)=>{const elem=document.getElementById('mud-drop-zone-'+id);elem.addEventListener('dragover',()=>event.preventDefault());elem.addEventListener('dragstart',()=>event.dataTransfer.setData('',event.target.id));},makeDropZonesNotRelative:()=>{var firstDropItems=Array.from(document.getElementsByClassName('mud-drop-item')).filter(x=>x.getAttribute('index')=="-1");for(let dropItem of firstDropItems){dropItem.style.position='static';}
|
||||||
|
const dropZones=document.getElementsByClassName('mud-drop-zone');for(let dropZone of dropZones){dropZone.style.position='unset';}},getDropZoneIdentifierOnPosition:(x,y)=>{const elems=document.elementsFromPoint(x,y);const dropZones=elems.filter(e=>e.classList.contains('mud-drop-zone'))
|
||||||
|
const dropZone=dropZones[0];if(dropZone){return dropZone.getAttribute('identifier')||"";}
|
||||||
|
return"";},getDropIndexOnPosition:(x,y,id)=>{const elems=document.elementsFromPoint(x,y);const dropItems=elems.filter(e=>e.classList.contains('mud-drop-item')&&e.id!=('mud-drop-item-'+id))
|
||||||
|
const dropItem=dropItems[0];if(dropItem){return dropItem.getAttribute('index')||"";}
|
||||||
|
return"";},makeDropZonesRelative:()=>{const dropZones=document.getElementsByClassName('mud-drop-zone');for(let dropZone of dropZones){dropZone.style.position='relative';}
|
||||||
|
var firstDropItems=Array.from(document.getElementsByClassName('mud-drop-item')).filter(x=>x.getAttribute('index')=="-1");for(let dropItem of firstDropItems){dropItem.style.position='relative';}},moveItemByDifference:(id,dx,dy)=>{const elem=document.getElementById('mud-drop-item-'+id);var tx=(parseFloat(elem.getAttribute('data-x'))||0)+dx;var ty=(parseFloat(elem.getAttribute('data-y'))||0)+dy;elem.style.webkitTransform=elem.style.transform='translate3d('+tx+'px, '+ty+'px, 10px)';elem.setAttribute('data-x',tx);elem.setAttribute('data-y',ty);},resetItem:(id)=>{const elem=document.getElementById('mud-drop-item-'+id);if(elem){elem.style.webkitTransform=elem.style.transform='';elem.setAttribute('data-x',0);elem.setAttribute('data-y',0);}}};class MudWindow{copyToClipboard(text){navigator.clipboard.writeText(text);}
|
||||||
|
changeCssById(id,css){var element=document.getElementById(id);if(element){element.className=css;}}
|
||||||
|
updateStyleProperty(elementId,propertyName,value){const element=document.getElementById(elementId);if(element){element.style.setProperty(propertyName,value);}}
|
||||||
|
changeGlobalCssVariable(name,newValue){document.documentElement.style.setProperty(name,newValue);}
|
||||||
|
open(args){window.open(args);}}
|
||||||
|
window.mudWindow=new MudWindow();class MudResizeListener{constructor(id){this.logger=function(message){};this.options={};this.throttleResizeHandlerId=-1;this.dotnet=undefined;this.breakpoint=-1;this.id=id;this.handleResize=this.throttleResizeHandler.bind(this);}
|
||||||
listenForResize(dotnetRef,options){if(this.dotnet){this.options=options;return;}
|
listenForResize(dotnetRef,options){if(this.dotnet){this.options=options;return;}
|
||||||
this.options=options;this.dotnet=dotnetRef;this.logger=options.enableLogging?console.log:(message)=>{};this.logger(`[MudBlazor]Reporting resize events at rate of:${(this.options||{}).reportRate||100}ms`);window.addEventListener("resize",this.handleResize,false);if(!this.options.suppressInitEvent){this.resizeHandler();}
|
this.options=options;this.dotnet=dotnetRef;this.logger=options.enableLogging?console.log:(message)=>{};this.logger(`[MudBlazor]Reporting resize events at rate of:${this.options.reportRate}ms`);window.addEventListener("resize",this.handleResize,false);if(!this.options.suppressInitEvent){this.resizeHandler();}
|
||||||
this.breakpoint=this.getBreakpoint(window.innerWidth);}
|
this.breakpoint=this.getBreakpoint(window.innerWidth);}
|
||||||
throttleResizeHandler(){clearTimeout(this.throttleResizeHandlerId);this.throttleResizeHandlerId=window.setTimeout(this.resizeHandler.bind(this),((this.options||{}).reportRate||100));}
|
throttleResizeHandler(){clearTimeout(this.throttleResizeHandlerId);this.throttleResizeHandlerId=window.setTimeout(this.resizeHandler.bind(this),this.options.reportRate);}
|
||||||
resizeHandler(){if(this.options.notifyOnBreakpointOnly){let bp=this.getBreakpoint(window.innerWidth);if(bp==this.breakpoint){return;}
|
resizeHandler(){if(this.options.notifyOnBreakpointOnly){let bp=this.getBreakpoint(window.innerWidth);if(bp==this.breakpoint){return;}
|
||||||
this.breakpoint=bp;}
|
this.breakpoint=bp;}
|
||||||
try{if(this.id){this.dotnet.invokeMethodAsync('RaiseOnResized',{height:window.innerHeight,width:window.innerWidth},this.getBreakpoint(window.innerWidth),this.id);}
|
try{if(this.id){this.dotnet.invokeMethodAsync('RaiseOnResized',{height:window.innerHeight,width:window.innerWidth},this.getBreakpoint(window.innerWidth),this.id);}
|
||||||
@@ -138,32 +172,7 @@ return 1;else
|
|||||||
return 0;}};window.mudResizeListener=new MudResizeListener();window.mudResizeListenerFactory={mapping:{},listenForResize:(dotnetRef,options,id)=>{var map=window.mudResizeListenerFactory.mapping;if(map[id]){return;}
|
return 0;}};window.mudResizeListener=new MudResizeListener();window.mudResizeListenerFactory={mapping:{},listenForResize:(dotnetRef,options,id)=>{var map=window.mudResizeListenerFactory.mapping;if(map[id]){return;}
|
||||||
var listener=new MudResizeListener(id);listener.listenForResize(dotnetRef,options);map[id]=listener;},cancelListener:(id)=>{var map=window.mudResizeListenerFactory.mapping;if(!map[id]){return;}
|
var listener=new MudResizeListener(id);listener.listenForResize(dotnetRef,options);map[id]=listener;},cancelListener:(id)=>{var map=window.mudResizeListenerFactory.mapping;if(!map[id]){return;}
|
||||||
var listener=map[id];listener.cancelListener();delete map[id];},cancelListeners:(ids)=>{for(let i=0;i<ids.length;i++){window.mudResizeListenerFactory.cancelListener(ids[i]);}},dispose(){var map=window.mudResizeListenerFactory.mapping;for(var id in map){window.mudResizeListenerFactory.cancelListener(id);}}}
|
var listener=map[id];listener.cancelListener();delete map[id];},cancelListeners:(ids)=>{for(let i=0;i<ids.length;i++){window.mudResizeListenerFactory.cancelListener(ids[i]);}},dispose(){var map=window.mudResizeListenerFactory.mapping;for(var id in map){window.mudResizeListenerFactory.cancelListener(id);}}}
|
||||||
const darkThemeMediaQuery=window.matchMedia("(prefers-color-scheme: dark)");window.darkModeChange=(dotNetHelper)=>{return darkThemeMediaQuery.matches;};function watchDarkThemeMedia(dotNetHelper){dotNetHelperTheme=dotNetHelper;window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change',function(e){dotNetHelperTheme.invokeMethodAsync('SystemPreferenceChanged',window.matchMedia("(prefers-color-scheme: dark)").matches);});}function setRippleOffset(event,target){const rect=target.getBoundingClientRect();const x=event.clientX-rect.left-rect.width/2;const y=event.clientY-rect.top-rect.height/2;target.style.setProperty("--mud-ripple-offset-x",`${x}px`);target.style.setProperty("--mud-ripple-offset-y",`${y}px`);}
|
window.mudpopoverHelper={calculatePopoverPosition:function(list,boundingRect,selfRect){let top=0;let left=0;if(list.indexOf('mud-popover-anchor-top-left')>=0){left=boundingRect.left;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-top-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-top-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-center-left')>=0){left=boundingRect.left;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-center-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-center-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-bottom-left')>=0){left=boundingRect.left;top=boundingRect.top+boundingRect.height;}else if(list.indexOf('mud-popover-anchor-bottom-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top+boundingRect.height;}else if(list.indexOf('mud-popover-anchor-bottom-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top+boundingRect.height;}
|
||||||
document.addEventListener("click",function(event){const target=event.target.closest(".mud-ripple");if(target){setRippleOffset(event,target);}});class MudResizeObserverFactory{constructor(){this._maps={};}
|
|
||||||
connect(id,dotNetRef,elements,elementIds,options){var existingEntry=this._maps[id];if(!existingEntry){var observer=new MudResizeObserver(dotNetRef,options);this._maps[id]=observer;}
|
|
||||||
var result=this._maps[id].connect(elements,elementIds);return result;}
|
|
||||||
disconnect(id,element){var existingEntry=this._maps[id];if(existingEntry){existingEntry.disconnect(element);}}
|
|
||||||
cancelListener(id){var existingEntry=this._maps[id];if(existingEntry){existingEntry.cancelListener();delete this._maps[id];}}}
|
|
||||||
class MudResizeObserver{constructor(dotNetRef,options){this.logger=options.enableLogging?console.log:(message)=>{};this.options=options;this._dotNetRef=dotNetRef
|
|
||||||
var delay=(this.options||{}).reportRate||200;this.throttleResizeHandlerId=-1;var observervedElements=[];this._observervedElements=observervedElements;this.logger('[MudBlazor | ResizeObserver] Observer initialized');this._resizeObserver=new ResizeObserver(entries=>{var changes=[];this.logger('[MudBlazor | ResizeObserver] changes detected');for(let entry of entries){var target=entry.target;var affectedObservedElement=observervedElements.find((x)=>x.element==target);if(affectedObservedElement){var size=entry.target.getBoundingClientRect();if(affectedObservedElement.isInitialized==true){changes.push({id:affectedObservedElement.id,size:size});}
|
|
||||||
else{affectedObservedElement.isInitialized=true;}}}
|
|
||||||
if(changes.length>0){if(this.throttleResizeHandlerId>=0){clearTimeout(this.throttleResizeHandlerId);}
|
|
||||||
this.throttleResizeHandlerId=window.setTimeout(this.resizeHandler.bind(this,changes),delay);}});}
|
|
||||||
resizeHandler(changes){try{this.logger("[MudBlazor | ResizeObserver] OnSizeChanged handler invoked");this._dotNetRef.invokeMethodAsync("OnSizeChanged",changes);}catch(error){this.logger("[MudBlazor | ResizeObserver] Error in OnSizeChanged handler:",{error});}}
|
|
||||||
connect(elements,ids){var result=[];this.logger('[MudBlazor | ResizeObserver] Start observing elements...');for(var i=0;i<elements.length;i++){var newEntry={element:elements[i],id:ids[i],isInitialized:false,};this.logger("[MudBlazor | ResizeObserver] Start observing element:",{newEntry});result.push(elements[i].getBoundingClientRect());this._observervedElements.push(newEntry);this._resizeObserver.observe(elements[i]);}
|
|
||||||
return result;}
|
|
||||||
disconnect(elementId){this.logger('[MudBlazor | ResizeObserver] Try to unobserve element with id',{elementId});var affectedObservedElement=this._observervedElements.find((x)=>x.id==elementId);if(affectedObservedElement){var element=affectedObservedElement.element;this._resizeObserver.unobserve(element);this.logger('[MudBlazor | ResizeObserver] Element found. Ubobserving size changes of element',{element});var index=this._observervedElements.indexOf(affectedObservedElement);this._observervedElements.splice(index,1);}}
|
|
||||||
cancelListener(){this.logger('[MudBlazor | ResizeObserver] Closing ResizeObserver. Detaching all observed elements');this._resizeObserver.disconnect();this._dotNetRef=undefined;}}
|
|
||||||
window.mudResizeObserver=new MudResizeObserverFactory();class MudScrollManager{scrollToYear(elementId,offset){let element=document.getElementById(elementId);if(element){element.parentNode.scrollTop=element.offsetTop-element.parentNode.offsetTop-element.scrollHeight*3;}}
|
|
||||||
scrollToListItem(elementId){let element=document.getElementById(elementId);if(element){let parent=element.parentElement;if(parent){parent.scrollTop=element.offsetTop;}}}
|
|
||||||
scrollTo(selector,left,top,behavior){let element=document.querySelector(selector)||document.documentElement;element.scrollTo({left,top,behavior});}
|
|
||||||
scrollIntoView(selector,behavior){let element=document.querySelector(selector)||document.documentElement;if(element)
|
|
||||||
element.scrollIntoView({behavior,block:'center',inline:'start'});}
|
|
||||||
scrollToBottom(selector,behavior){let element=document.querySelector(selector);if(element)
|
|
||||||
element.scrollTop=element.scrollHeight;else
|
|
||||||
window.scrollTo(0,document.body.scrollHeight);}
|
|
||||||
lockScroll(selector,lockclass){let element=document.querySelector(selector)||document.body;let hasScrollBar=window.innerWidth>document.body.clientWidth;if(hasScrollBar){element.classList.add(lockclass);}else{let lockClassNoPadding=lockclass+"-no-padding";element.classList.add(lockClassNoPadding);}}
|
|
||||||
unlockScroll(selector,lockclass){let element=document.querySelector(selector)||document.body;element.classList.remove(lockclass);element.classList.remove(lockclass+"-no-padding");}};window.mudScrollManager=new MudScrollManager();window.mudpopoverHelper={calculatePopoverPosition:function(list,boundingRect,selfRect){let top=0;let left=0;if(list.indexOf('mud-popover-anchor-top-left')>=0){left=boundingRect.left;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-top-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-top-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top;}else if(list.indexOf('mud-popover-anchor-center-left')>=0){left=boundingRect.left;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-center-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-center-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top+boundingRect.height/2;}else if(list.indexOf('mud-popover-anchor-bottom-left')>=0){left=boundingRect.left;top=boundingRect.top+boundingRect.height;}else if(list.indexOf('mud-popover-anchor-bottom-center')>=0){left=boundingRect.left+boundingRect.width/2;top=boundingRect.top+boundingRect.height;}else if(list.indexOf('mud-popover-anchor-bottom-right')>=0){left=boundingRect.left+boundingRect.width;top=boundingRect.top+boundingRect.height;}
|
|
||||||
let offsetX=0;let offsetY=0;if(list.indexOf('mud-popover-top-left')>=0){offsetX=0;offsetY=0;}else if(list.indexOf('mud-popover-top-center')>=0){offsetX=-selfRect.width/2;offsetY=0;}else if(list.indexOf('mud-popover-top-right')>=0){offsetX=-selfRect.width;offsetY=0;}
|
let offsetX=0;let offsetY=0;if(list.indexOf('mud-popover-top-left')>=0){offsetX=0;offsetY=0;}else if(list.indexOf('mud-popover-top-center')>=0){offsetX=-selfRect.width/2;offsetY=0;}else if(list.indexOf('mud-popover-top-right')>=0){offsetX=-selfRect.width;offsetY=0;}
|
||||||
else if(list.indexOf('mud-popover-center-left')>=0){offsetX=0;offsetY=-selfRect.height/2;}else if(list.indexOf('mud-popover-center-center')>=0){offsetX=-selfRect.width/2;offsetY=-selfRect.height/2;}else if(list.indexOf('mud-popover-center-right')>=0){offsetX=-selfRect.width;offsetY=-selfRect.height/2;}
|
else if(list.indexOf('mud-popover-center-left')>=0){offsetX=0;offsetY=-selfRect.height/2;}else if(list.indexOf('mud-popover-center-center')>=0){offsetX=-selfRect.width/2;offsetY=-selfRect.height/2;}else if(list.indexOf('mud-popover-center-right')>=0){offsetX=-selfRect.width;offsetY=-selfRect.height/2;}
|
||||||
else if(list.indexOf('mud-popover-bottom-left')>=0){offsetX=0;offsetY=-selfRect.height;}else if(list.indexOf('mud-popover-bottom-center')>=0){offsetX=-selfRect.width/2;offsetY=-selfRect.height;}else if(list.indexOf('mud-popover-bottom-right')>=0){offsetX=-selfRect.width;offsetY=-selfRect.height;}
|
else if(list.indexOf('mud-popover-bottom-left')>=0){offsetX=0;offsetY=-selfRect.height;}else if(list.indexOf('mud-popover-bottom-center')>=0){offsetX=-selfRect.width/2;offsetY=-selfRect.height;}else if(list.indexOf('mud-popover-bottom-right')>=0){offsetX=-selfRect.width;offsetY=-selfRect.height;}
|
||||||
@@ -207,72 +216,72 @@ dispose(){for(var i in this.map){disconnect(i);}
|
|||||||
this.contentObserver.disconnect();this.contentObserver=null;}
|
this.contentObserver.disconnect();this.contentObserver=null;}
|
||||||
getAllObservedContainers(){const result=[];for(var i in this.map){result.push(i);}
|
getAllObservedContainers(){const result=[];for(var i in this.map){result.push(i);}
|
||||||
return result;}}
|
return result;}}
|
||||||
window.mudPopover=new MudPopover();window.addEventListener('scroll',()=>{window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-fixed');window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-overflow-flip-always');});window.addEventListener('resize',()=>{window.mudpopoverHelper.placePopoverByClassSelector();});window.mudInputAutoGrow={initAutoGrow:(elem,maxLines)=>{const compStyle=getComputedStyle(elem);const lineHeight=parseFloat(compStyle.getPropertyValue('line-height'));let maxHeight=0;elem.updateParameters=function(newMaxLines){if(newMaxLines>0){maxHeight=lineHeight*newMaxLines;}else{maxHeight=0;}}
|
window.mudPopover=new MudPopover();window.addEventListener('scroll',()=>{window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-fixed');window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-overflow-flip-always');});window.addEventListener('resize',()=>{window.mudpopoverHelper.placePopoverByClassSelector();});class MudFileUpload{openFilePicker(id){const element=document.getElementById(id);if(!element){return;}
|
||||||
elem.adjustAutoGrowHeight=function(didReflow=false){const scrollTops=[];let curElem=elem;while(curElem&&curElem.parentNode&&curElem.parentNode instanceof Element){if(curElem.parentNode.scrollTop){scrollTops.push([curElem.parentNode,curElem.parentNode.scrollTop]);}
|
try{element.showPicker();}catch(error){element.click();}}}
|
||||||
curElem=curElem.parentNode;}
|
window.mudFileUpload=new MudFileUpload();function setRippleOffset(event,target){const rect=target.getBoundingClientRect();const x=event.clientX-rect.left-rect.width/2;const y=event.clientY-rect.top-rect.height/2;target.style.setProperty("--mud-ripple-offset-x",`${x}px`);target.style.setProperty("--mud-ripple-offset-y",`${y}px`);}
|
||||||
elem.style.height=0;if(didReflow){elem.style.textAlign=null;}
|
document.addEventListener("click",function(event){const target=event.target.closest(".mud-ripple");if(target){setRippleOffset(event,target);}});class MudScrollManager{scrollToYear(elementId,offset){let element=document.getElementById(elementId);if(element){element.parentNode.scrollTop=element.offsetTop-element.parentNode.offsetTop-element.scrollHeight*3;}}
|
||||||
let minHeight=lineHeight*elem.rows;let newHeight=Math.max(minHeight,elem.scrollHeight);let initialOverflowY=elem.style.overflowY;if(maxHeight>0&&newHeight>maxHeight){elem.style.overflowY='auto';newHeight=maxHeight;}else{elem.style.overflowY='hidden';}
|
scrollToListItem(elementId){let element=document.getElementById(elementId);if(element){let parent=element.parentElement;if(parent){parent.scrollTop=element.offsetTop;}}}
|
||||||
elem.style.height=newHeight+"px";scrollTops.forEach(([node,scrollTop])=>{node.style.scrollBehavior='auto';node.scrollTop=scrollTop;node.style.scrollBehavior=null;});if(!didReflow&&initialOverflowY!==elem.style.overflowY&&elem.style.overflowY==='hidden'){elem.style.textAlign='end';elem.adjustAutoGrowHeight(true);}}
|
scrollTo(selector,left,top,behavior){let element=document.querySelector(selector)||document.documentElement;element.scrollTo({left,top,behavior});}
|
||||||
elem.restoreToInitialState=function(){elem.removeEventListener('input',elem.adjustAutoGrowHeight);elem.style.overflowY=null;elem.style.height=null;}
|
scrollIntoView(selector,behavior){let element=document.querySelector(selector)||document.documentElement;if(element)
|
||||||
elem.addEventListener('input',elem.adjustAutoGrowHeight);window.addEventListener('resize',elem.adjustAutoGrowHeight);elem.updateParameters(maxLines);elem.adjustAutoGrowHeight();},adjustHeight:(elem)=>{if(typeof elem.adjustAutoGrowHeight==='function'){elem.adjustAutoGrowHeight();}},updateParams:(elem,maxLines)=>{if(typeof elem.updateParameters==='function'){elem.updateParameters(maxLines);}
|
element.scrollIntoView({behavior,block:'center',inline:'start'});}
|
||||||
if(typeof elem.adjustAutoGrowHeight==='function'){elem.adjustAutoGrowHeight();}},destroy:(elem)=>{window.removeEventListener('resize',elem.adjustAutoGrowHeight);if(typeof elem.restoreToInitialState==='function'){elem.restoreToInitialState();}}}
|
scrollToBottom(selector,behavior){let element=document.querySelector(selector);if(element){element.scrollTo({top:element.scrollHeight,behavior:behavior});}else{window.scrollTo({top:document.body.scrollHeight,behavior:behavior});}}
|
||||||
class MudWindow{copyToClipboard(text){navigator.clipboard.writeText(text);}
|
lockScroll(selector,lockclass){let element=document.querySelector(selector)||document.body;let hasScrollBar=window.innerWidth>document.body.clientWidth;if(hasScrollBar){element.classList.add(lockclass);}else{let lockClassNoPadding=lockclass+"-no-padding";element.classList.add(lockClassNoPadding);}}
|
||||||
changeCssById(id,css){var element=document.getElementById(id);if(element){element.className=css;}}
|
unlockScroll(selector,lockclass){let element=document.querySelector(selector)||document.body;element.classList.remove(lockclass);element.classList.remove(lockclass+"-no-padding");}};window.mudScrollManager=new MudScrollManager();class MudJsEventFactory{connect(dotNetRef,elementId,options){if(!elementId)
|
||||||
updateStyleProperty(elementId,propertyName,value){const element=document.getElementById(elementId);if(element){element.style.setProperty(propertyName,value);}}
|
throw"[MudBlazor | JsEvent] elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
||||||
changeGlobalCssVariable(name,newValue){document.documentElement.style.setProperty(name,newValue);}
|
throw"[MudBlazor | JsEvent] no element found for id: "+elementId;if(!element.mudJsEvent)
|
||||||
open(args){window.open(args);}};window.mudWindow=new MudWindow();class MudElementReference{constructor(){this.listenerId=0;this.eventListeners={};}
|
element.mudJsEvent=new MudJsEvent(dotNetRef,options);element.mudJsEvent.connect(element);}
|
||||||
focus(element){if(element)
|
disconnect(elementId){var element=document.getElementById(elementId);if(!element||!element.mudJsEvent)
|
||||||
{element.focus();}}
|
return;element.mudJsEvent.disconnect();}
|
||||||
blur(element){if(element){element.blur();}}
|
subscribe(elementId,eventName){if(!elementId)
|
||||||
focusFirst(element,skip=0,min=0){if(element)
|
throw"[MudBlazor | JsEvent] elementId: expected element id!";var element=document.getElementById(elementId);if(!element)
|
||||||
{let tabbables=getTabbableElements(element);if(tabbables.length<=min)
|
throw"[MudBlazor | JsEvent] no element found for id: "+elementId;if(!element.mudJsEvent)
|
||||||
element.focus();else
|
throw"[MudBlazor | JsEvent] please connect before subscribing"
|
||||||
tabbables[skip].focus();}}
|
element.mudJsEvent.subscribe(eventName);}
|
||||||
focusLast(element,skip=0,min=0){if(element)
|
unsubscribe(elementId,eventName){var element=document.getElementById(elementId);if(!element||!element.mudJsEvent)
|
||||||
{let tabbables=getTabbableElements(element);if(tabbables.length<=min)
|
return;element.mudJsEvent.unsubscribe(element,eventName);}}
|
||||||
element.focus();else
|
window.mudJsEvent=new MudJsEventFactory();class MudJsEvent{constructor(dotNetRef,options){this._dotNetRef=dotNetRef;this._options=options||{};this.logger=options.enableLogging?console.log:(message)=>{};this.logger('[MudBlazor | JsEvent] Initialized',{options});this._subscribedEvents={};}
|
||||||
tabbables[tabbables.length-skip-1].focus();}}
|
connect(element){if(!this._options)
|
||||||
saveFocus(element){if(element)
|
return;if(!this._options.targetClass)
|
||||||
{element['mudblazor_savedFocus']=document.activeElement;}}
|
throw"_options.targetClass: css class name expected";if(this._observer){return;}
|
||||||
restoreFocus(element){if(element)
|
var targetClass=this._options.targetClass;this.logger('[MudBlazor | JsEvent] Start observing DOM of element for changes to child with class ',{element,targetClass});this._element=element;this._observer=new MutationObserver(this.onDomChanged);this._observer.mudJsEvent=this;this._observer.observe(this._element,{attributes:false,childList:true,subtree:true});this._observedChildren=[];}
|
||||||
{let previous=element['mudblazor_savedFocus'];delete element['mudblazor_savedFocus']
|
disconnect(){if(!this._observer)
|
||||||
if(previous)
|
return;this.logger('[MudBlazor | JsEvent] disconnect mutation observer and event handler ');this._observer.disconnect();this._observer=null;for(const child of this._observedChildren)
|
||||||
previous.focus();}}
|
this.detachHandlers(child);}
|
||||||
selectRange(element,pos1,pos2){if(element)
|
subscribe(eventName){if(this._subscribedEvents[eventName]){return;}
|
||||||
{if(element.createTextRange){let selRange=element.createTextRange();selRange.collapse(true);selRange.moveStart('character',pos1);selRange.moveEnd('character',pos2);selRange.select();}else if(element.setSelectionRange){element.setSelectionRange(pos1,pos2);}else if(element.selectionStart){element.selectionStart=pos1;element.selectionEnd=pos2;}
|
var element=this._element;var targetClass=this._options.targetClass;this._subscribedEvents[eventName]=true;for(const child of element.getElementsByClassName(targetClass)){this.attachHandlers(child);}}
|
||||||
element.focus();}}
|
unsubscribe(eventName){if(!this._observer)
|
||||||
select(element){if(element)
|
return;this.logger('[MudBlazor | JsEvent] unsubscribe event handler '+eventName);this._observer.disconnect();this._observer=null;this._subscribedEvents[eventName]=false;for(const child of this._observedChildren){this.detachHandler(child,eventName);}}
|
||||||
{element.select();}}
|
attachHandlers(child){child.mudJsEvent=this;for(var eventName of Object.getOwnPropertyNames(this._subscribedEvents)){if(!this._subscribedEvents[eventName])
|
||||||
getBoundingClientRect(element){if(!element)return;var rect=JSON.parse(JSON.stringify(element.getBoundingClientRect()));rect.scrollY=window.scrollY||document.documentElement.scrollTop;rect.scrollX=window.scrollX||document.documentElement.scrollLeft;rect.windowHeight=window.innerHeight;rect.windowWidth=window.innerWidth;return rect;}
|
continue;this.logger('[MudBlazor | JsEvent] attaching event '+eventName,child);child.addEventListener(eventName,this.eventHandler);}
|
||||||
changeCss(element,css){if(element)
|
if(this._observedChildren.indexOf(child)<0)
|
||||||
{element.className=css;}}
|
this._observedChildren.push(child);}
|
||||||
removeEventListener(element,event,eventId){element.removeEventListener(event,this.eventListeners[eventId]);delete this.eventListeners[eventId];}
|
detachHandler(child,eventName){this.logger('[MudBlazor | JsEvent] detaching handler '+eventName,child);child.removeEventListener(eventName,this.eventHandler);}
|
||||||
addDefaultPreventingHandler(element,eventName){let listener=function(e){e.preventDefault();}
|
detachHandlers(child){this.logger('[MudBlazor | JsEvent] detaching handlers ',child);for(var eventName of Object.getOwnPropertyNames(this._subscribedEvents)){if(!this._subscribedEvents[eventName])
|
||||||
element.addEventListener(eventName,listener,{passive:false});this.eventListeners[++this.listenerId]=listener;return this.listenerId;}
|
continue;child.removeEventListener(eventName,this.eventHandler);}
|
||||||
removeDefaultPreventingHandler(element,eventName,listenerId){this.removeEventListener(element,eventName,listenerId);}
|
this._observedChildren=this._observedChildren.filter(x=>x!==child);}
|
||||||
addDefaultPreventingHandlers(element,eventNames){let listeners=[];for(const eventName of eventNames){let listenerId=this.addDefaultPreventingHandler(element,eventName);listeners.push(listenerId);}
|
onDomChanged(mutationsList,observer){var self=this.mudJsEvent;var targetClass=self._options.targetClass;for(const mutation of mutationsList){for(const element of mutation.addedNodes){if(element.classList&&element.classList.contains(targetClass)){if(!self._options.TagName||element.tagName==self._options.TagName)
|
||||||
return listeners;}
|
self.attachHandlers(element);}}
|
||||||
removeDefaultPreventingHandlers(element,eventNames,listenerIds){for(let index=0;index<eventNames.length;++index){const eventName=eventNames[index];const listenerId=listenerIds[index];this.removeDefaultPreventingHandler(element,eventName,listenerId);}}};window.mudElementRef=new MudElementReference();class MudScrollSpy{constructor(){this.scrollToSectionRequested=null;this.lastKnowElement=null;this.handlerRef=null;}
|
for(const element of mutation.removedNodes){if(element.classList&&element.classList.contains(targetClass)){if(!self._options.tagName||element.tagName==self._options.tagName)
|
||||||
spying(dotnetReference,selector){this.scrollToSectionRequested=null;this.lastKnowElement=null;this.handlerRef=this.handleScroll.bind(this,selector,dotnetReference);document.addEventListener('scroll',this.handlerRef,true);window.addEventListener('resize',this.handlerRef,true);}
|
self.detachHandlers(element);}}}}
|
||||||
handleScroll(dotnetReference,selector,event){const elements=document.getElementsByClassName(selector);if(elements.length===0){return;}
|
eventHandler(e){var self=this.mudJsEvent;var eventName=e.type;self.logger('[MudBlazor | JsEvent] "'+eventName+'"',e);self["on"+eventName](self,e);}
|
||||||
const center=window.innerHeight/2.0;let minDifference=Number.MAX_SAFE_INTEGER;let elementId='';for(let i=0;i<elements.length;i++){const element=elements[i];const rect=element.getBoundingClientRect();const diff=Math.abs(rect.top-center);if(diff<minDifference){minDifference=diff;elementId=element.id;}}
|
onkeyup(self,e){const caretPosition=e.target.selectionStart;const invoke=self._subscribedEvents["keyup"];if(invoke){self._dotNetRef.invokeMethodAsync('OnCaretPositionChanged',caretPosition);}}
|
||||||
if(document.getElementById(elementId).getBoundingClientRect().top<window.innerHeight*0.8===false){return;}
|
onclick(self,e){const caretPosition=e.target.selectionStart;const invoke=self._subscribedEvents["click"];if(invoke){self._dotNetRef.invokeMethodAsync('OnCaretPositionChanged',caretPosition);}}
|
||||||
if(this.scrollToSectionRequested!=null){if(this.scrollToSectionRequested==' '&&window.scrollY==0){this.scrollToSectionRequested=null;}
|
onpaste(self,e){const invoke=self._subscribedEvents["paste"];if(invoke){e.preventDefault();e.stopPropagation();const text=(e.originalEvent||e).clipboardData.getData('text/plain');self._dotNetRef.invokeMethodAsync('OnPaste',text);}}
|
||||||
else{if(elementId===this.scrollToSectionRequested){this.scrollToSectionRequested=null;}}
|
onselect(self,e){const invoke=self._subscribedEvents["select"];if(invoke){const start=e.target.selectionStart;const end=e.target.selectionEnd;if(start===end)
|
||||||
return;}
|
return;self._dotNetRef.invokeMethodAsync('OnSelect',start,end);}}}
|
||||||
if(elementId!=this.lastKnowElement){this.lastKnowElement=elementId;history.replaceState(null,'',window.location.pathname+"#"+elementId);dotnetReference.invokeMethodAsync('SectionChangeOccured',elementId);}}
|
class MudThrottledEventManager{constructor(){this.mapper={};}
|
||||||
activateSection(sectionId){const element=document.getElementById(sectionId);if(element){this.lastKnowElement=sectionId;history.replaceState(null,'',window.location.pathname+"#"+sectionId);}}
|
subscribe(eventName,elementId,projection,throotleInterval,key,properties,dotnetReference){const handlerRef=this.throttleEventHandler.bind(this,key);let elem=document.getElementById(elementId);if(elem){elem.addEventListener(eventName,handlerRef,false);let projector=null;if(projection){const parts=projection.split('.');let functionPointer=window;let functionReferenceFound=true;if(parts.length==0||parts.length==1){functionPointer=functionPointer[projection];}
|
||||||
scrollToSection(sectionId){if(sectionId){let element=document.getElementById(sectionId);if(element){this.scrollToSectionRequested=sectionId;element.scrollIntoView({behavior:'smooth',block:'center',inline:'start'});}}
|
else{for(let i=0;i<parts.length;i++){functionPointer=functionPointer[parts[i]];if(!functionPointer){functionReferenceFound=false;break;}}}
|
||||||
else{window.scrollTo({top:0,behavior:'smooth'});this.scrollToSectionRequested=' ';}}
|
if(functionReferenceFound===true){projector=functionPointer;}}
|
||||||
unspy(){document.removeEventListener('scroll',this.handlerRef,true);window.removeEventListener('resize',this.handlerRef,true);}};window.mudScrollSpy=new MudScrollSpy();window.getTabbableElements=(element)=>{return element.querySelectorAll("a[href]:not([tabindex='-1']),"+"area[href]:not([tabindex='-1']),"+"button:not([disabled]):not([tabindex='-1']),"+"input:not([disabled]):not([tabindex='-1']):not([type='hidden']),"+"select:not([disabled]):not([tabindex='-1']),"+"textarea:not([disabled]):not([tabindex='-1']),"+"iframe:not([tabindex='-1']),"+"details:not([tabindex='-1']),"+"[tabindex]:not([tabindex='-1']),"+"[contentEditable=true]:not([tabindex='-1'])");};window.serializeParameter=(data,spec)=>{if(typeof data=="undefined"||data===null){return null;}
|
this.mapper[key]={eventName:eventName,handler:handlerRef,delay:throotleInterval,timerId:-1,reference:dotnetReference,elementId:elementId,properties:properties,projection:projector,};}}
|
||||||
if(typeof data==="number"||typeof data==="string"||typeof data=="boolean"){return data;}
|
subscribeGlobal(eventName,throotleInterval,key,properties,dotnetReference){let handlerRef=throotleInterval>0?this.throttleEventHandler.bind(this,key):this.eventHandler.bind(this,key);document.addEventListener(eventName,handlerRef,false);this.mapper[key]={eventName:eventName,handler:handlerRef,delay:throotleInterval,timerId:-1,reference:dotnetReference,elementId:document,properties:properties,projection:null,};}
|
||||||
let res=(Array.isArray(data))?[]:{};if(!spec){spec="*";}
|
throttleEventHandler(key,event){const entry=this.mapper[key];if(!entry){return;}
|
||||||
for(let i in data){let currentMember=data[i];if(typeof currentMember==='function'||currentMember===null){continue;}
|
clearTimeout(entry.timerId);entry.timerId=window.setTimeout(this.eventHandler.bind(this,key,event),entry.delay);}
|
||||||
let currentMemberSpec;if(spec!="*"){currentMemberSpec=Array.isArray(data)?spec:spec[i];if(!currentMemberSpec){continue;}}else{currentMemberSpec="*"}
|
eventHandler(key,event){const entry=this.mapper[key];if(!entry){return;}
|
||||||
if(typeof currentMember==='object'){if(Array.isArray(currentMember)||currentMember.length){res[i]=[];for(let j=0;j<currentMember.length;j++){const arrayItem=currentMember[j];if(typeof arrayItem==='object'){res[i].push(this.serializeParameter(arrayItem,currentMemberSpec));}else{res[i].push(arrayItem);}}}else{if(currentMember.length===0){res[i]=[];}else{res[i]=this.serializeParameter(currentMember,currentMemberSpec);}}}else{if(currentMember===Infinity){currentMember="Infinity";}
|
var elem=document.getElementById(entry.elementId);if(elem!=event.srcElement&&entry.elementId!=document){return;}
|
||||||
if(currentMember!==null){res[i]=currentMember;}}}
|
const eventEntry={};for(var i=0;i<entry.properties.length;i++){eventEntry[entry.properties[i]]=event[entry.properties[i]];}
|
||||||
return res;};class MudScrollListener{constructor(){this.throttleScrollHandlerId=-1;this.handlerRef=null;}
|
if(entry.projection){if(typeof entry.projection==="function"){entry.projection.apply(null,[eventEntry,event]);}}
|
||||||
listenForScroll(dotnetReference,selector){let element=selector?document.querySelector(selector):document;this.handlerRef=this.throttleScrollHandler.bind(this,dotnetReference);element.addEventListener('scroll',this.handlerRef,false);}
|
entry.reference.invokeMethodAsync('OnEventOccur',key,JSON.stringify(eventEntry));}
|
||||||
throttleScrollHandler(dotnetReference,event){clearTimeout(this.throttleScrollHandlerId);this.throttleScrollHandlerId=window.setTimeout(this.scrollHandler.bind(this,dotnetReference,event),100);}
|
unsubscribe(key){const entry=this.mapper[key];if(!entry){return;}
|
||||||
scrollHandler(dotnetReference,event){try{let element=event.target;let scrollTop=element.scrollTop;let scrollHeight=element.scrollHeight;let scrollWidth=element.scrollWidth;let scrollLeft=element.scrollLeft;let nodeName=element.nodeName;let firstChild=element.firstElementChild;let firstChildBoundingClientRect=firstChild.getBoundingClientRect();dotnetReference.invokeMethodAsync('RaiseOnScroll',{firstChildBoundingClientRect,scrollLeft,scrollTop,scrollHeight,scrollWidth,nodeName,});}catch(error){console.log('[MudBlazor] Error in scrollHandler:',{error});}}
|
entry.reference=null;if(document==entry.elementId){document.removeEventListener(entry.eventName,entry.handler,false);}else{const elem=document.getElementById(entry.elementId);if(elem){elem.removeEventListener(entry.eventName,entry.handler,false);}}
|
||||||
cancelListener(selector){let element=selector?document.querySelector(selector):document;element.removeEventListener('scroll',this.handlerRef);}};window.mudScrollListener=new MudScrollListener();
|
delete this.mapper[key];}};window.mudThrottledEventManager=new MudThrottledEventManager();window.mudEventProjections={correctOffset:function(eventEntry,event){var target=event.target.getBoundingClientRect();eventEntry.offsetX=event.clientX-target.x;eventEntry.offsetY=event.clientY-target.y;}};
|
||||||
+7
-7
@@ -1,9 +1,9 @@
|
|||||||
0.8.2
|
0.8.5
|
||||||
2024-07-16 18:03:04 UTC
|
2024-07-28 16:44:01 UTC
|
||||||
164
|
167
|
||||||
8.0.107 (commit 1bdaef7265)
|
8.0.107 (commit 1bdaef7265)
|
||||||
8.0.7 (commit 2aade6beb0)
|
8.0.7 (commit 2aade6beb0)
|
||||||
1.79.0 (commit 129f3b996)
|
1.80.0 (commit 051478957)
|
||||||
6.20.0
|
7.4.0
|
||||||
1.6.1
|
1.7.1
|
||||||
c92ce49af2d, release
|
c1b92a05fc7, release
|
||||||
Generated
+640
-539
File diff suppressed because it is too large.
Load diff
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mindwork-ai-studio"
|
name = "mindwork-ai-studio"
|
||||||
version = "0.8.2"
|
version = "0.8.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "MindWork AI Studio"
|
description = "MindWork AI Studio"
|
||||||
authors = ["Thorsten Sommer"]
|
authors = ["Thorsten Sommer"]
|
||||||
@@ -9,13 +9,13 @@ authors = ["Thorsten Sommer"]
|
|||||||
tauri-build = { version = "1.5", features = [] }
|
tauri-build = { version = "1.5", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "1.6", features = [ "updater", "http-all", "shell-sidecar", "path-all", "shell-open"] }
|
tauri = { version = "1.7.1", features = [ "updater", "http-all", "shell-sidecar", "path-all", "shell-open"] }
|
||||||
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
keyring = "2"
|
keyring = "2"
|
||||||
arboard = "3.4.0"
|
arboard = "3.4.0"
|
||||||
tokio = "1.37.0"
|
tokio = "1.39"
|
||||||
flexi_logger = "0.28"
|
flexi_logger = "0.28"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
|
|||||||
+15
-1
@@ -15,6 +15,7 @@ use tauri::api::process::{Command, CommandChild, CommandEvent};
|
|||||||
use tauri::utils::config::AppUrl;
|
use tauri::utils::config::AppUrl;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use flexi_logger::{AdaptiveFormat, Logger};
|
use flexi_logger::{AdaptiveFormat, Logger};
|
||||||
|
use keyring::error::Error::NoEntry;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use tauri::updater::UpdateResponse;
|
use tauri::updater::UpdateResponse;
|
||||||
|
|
||||||
@@ -292,7 +293,7 @@ enum ServerEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_dev() -> bool {
|
pub fn is_dev() -> bool {
|
||||||
cfg!(dev)
|
cfg!(debug_assertions)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_prod() -> bool {
|
pub fn is_prod() -> bool {
|
||||||
@@ -454,19 +455,31 @@ fn delete_secret(destination: String, user_name: String) -> DeleteSecretResponse
|
|||||||
let service = format!("mindwork-ai-studio::{}", destination);
|
let service = format!("mindwork-ai-studio::{}", destination);
|
||||||
let entry = Entry::new(service.as_str(), user_name.as_str()).unwrap();
|
let entry = Entry::new(service.as_str(), user_name.as_str()).unwrap();
|
||||||
let result = entry.delete_password();
|
let result = entry.delete_password();
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
warn!("Secret for {service} and user {user_name} was deleted successfully.");
|
warn!("Secret for {service} and user {user_name} was deleted successfully.");
|
||||||
DeleteSecretResponse {
|
DeleteSecretResponse {
|
||||||
success: true,
|
success: true,
|
||||||
|
was_entry_found: true,
|
||||||
issue: String::from(""),
|
issue: String::from(""),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Err(NoEntry) => {
|
||||||
|
warn!("No secret for {service} and user {user_name} was found.");
|
||||||
|
DeleteSecretResponse {
|
||||||
|
success: true,
|
||||||
|
was_entry_found: false,
|
||||||
|
issue: String::from(""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to delete secret for {service} and user {user_name}: {e}.");
|
error!("Failed to delete secret for {service} and user {user_name}: {e}.");
|
||||||
DeleteSecretResponse {
|
DeleteSecretResponse {
|
||||||
success: false,
|
success: false,
|
||||||
|
was_entry_found: false,
|
||||||
issue: e.to_string(),
|
issue: e.to_string(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -476,6 +489,7 @@ fn delete_secret(destination: String, user_name: String) -> DeleteSecretResponse
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct DeleteSecretResponse {
|
struct DeleteSecretResponse {
|
||||||
success: bool,
|
success: bool,
|
||||||
|
was_entry_found: bool,
|
||||||
issue: String,
|
issue: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "MindWork AI Studio",
|
"productName": "MindWork AI Studio",
|
||||||
"version": "0.8.2"
|
"version": "0.8.5"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
Reference in new issue
Block a user