push to remote
This commit is contained in:
parent
ca62eafaad
commit
ae17d414e4
33 changed files with 2492 additions and 782 deletions
|
|
@ -1,13 +1,13 @@
|
|||
## WORKSPACE EXECUTIVE SUMMARY (YAML)
|
||||
# Generated: 2026-05-21T10:41:25.5071284+02:00
|
||||
# Generated: 2026-05-23T07:48:43.1838976+02:00
|
||||
# Root: E:\ollama_net\ollama\AuthorBuddy.Web
|
||||
Architecture:
|
||||
Type: Backend (C#/.NET)
|
||||
Scale: 38 relevant source files
|
||||
Scale: 42 relevant source files
|
||||
Components: 0
|
||||
Controllers: 0
|
||||
Models: 8
|
||||
Services: 16
|
||||
Services: 18
|
||||
---
|
||||
- File: AuthorBuddy.Web.csproj
|
||||
Preview: "<Project Sdk='Microsoft.NET.Sdk.Web'> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>en..."
|
||||
|
|
@ -20,68 +20,109 @@ Architecture:
|
|||
- File: Program.cs
|
||||
Preview: "using AuthorBuddy.Web.Components; using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Services; using LiteDB; using Microsoft.AspNetCore.Authenticatio..."
|
||||
- File: Data\DocumentMetaEntity.cs
|
||||
Symbols: [DocumentMetaEntity]
|
||||
Preview: "namespace AuthorBuddy.Web.Data; public class DocumentMetaEntity { public int Id { get; set; } public int? ProjectId { get; set; } public string ..."
|
||||
- File: Data\DocumentVector.cs
|
||||
Symbols: [DocumentVector]
|
||||
Preview: "namespace AuthorBuddy.Web.Data; public class DocumentVector { public int Id { get; set; } public int DocumentMetaId { get; set; } public int Pro..."
|
||||
- File: Data\ProjectEntity.cs
|
||||
Symbols: [ProjectEntity]
|
||||
Preview: "namespace AuthorBuddy.Web.Data; public class ProjectEntity { public int Id { get; set; } public string Name { get; set; } = string.Empty; public..."
|
||||
- File: Data\SettingEntity.cs
|
||||
Symbols: [SettingEntity]
|
||||
Preview: "using LiteDB; namespace AuthorBuddy.Web.Data; public class SettingEntity { public int Id { get; set; } public string Key { get; set; } = string.Em..."
|
||||
- File: Data\UserEntity.cs
|
||||
Preview: "namespace AuthorBuddy.Web.Data; public class UserEntity { public int Id { get; set; } public string Name { get; set; } = string.Empty; public bo..."
|
||||
Symbols: [UserEntity]
|
||||
Preview: "namespace AuthorBuddy.Web.Data; public class UserEntity { public int Id { get; set; } public string Name { get; set; } = string.Empty; public st..."
|
||||
- File: Models\Chapter.cs
|
||||
Symbols: [Chapter]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public class Chapter { public string Title { get; set; } = string.Empty; public string FilePath { get; set; } = ..."
|
||||
- File: Models\Constants.cs
|
||||
Symbols: [Constants]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public static class Constants { public static readonly string[] SubFolders = { '00_Drafts', '01_Fakten/Per..."
|
||||
- File: Models\FileTreeItem.cs
|
||||
Symbols: [FileTreeItem]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public class FileTreeItem { public string Name { get; set; } = string.Empty; public string FullPath { get; set; ..."
|
||||
- File: Models\LLM_Model.cs
|
||||
Symbols: [LLM_Model, LLM_Model]
|
||||
Preview: "using System.Text.Json; namespace AuthorBuddy.Web.Models { public class LLM_Model { public LLM_Model(JsonElement model) { if (mode..."
|
||||
- File: Models\ModelStatus.cs
|
||||
Symbols: [ModelStatus]
|
||||
Preview: " //namespace AuthorBuddy.Web.Models; //public class ModelStatus //{ // public string Status { get; private set; } = 'Unknown'; // public double Prog..."
|
||||
- File: Models\OllamaSettings.cs
|
||||
Symbols: [OllamaSettings]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public class OllamaSettings { public string StyleModel { get; set; } = 'gemma4:e4b'; public string EmbedModel { ..."
|
||||
- File: Models\Project.cs
|
||||
Symbols: [Project]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public class Project { public int Id { get; internal set; } public string Name { get; internal set; } = string.E..."
|
||||
- File: Models\WikipediaResult.cs
|
||||
Symbols: [WikipediaResult]
|
||||
Preview: "namespace AuthorBuddy.Web.Models; public class WikipediaResult { public string Title { get; set; } = string.Empty; public string Snippet { get; se..."
|
||||
- File: Properties\launchSettings.json
|
||||
Preview: "{ '$schema': 'https://json.schemastore.org/launchsettings.json', 'profiles': { 'http': { 'commandName': 'Project', 'dotnetRunMessages': ..."
|
||||
- File: Resources\de.json
|
||||
Preview: "{ 'common.status.ready': 'Bereit', 'common.cancel': 'Abbrechen', 'common.error': 'Fehler:', 'common.copy': 'Kopieren', 'common.status.error': 'Fe..."
|
||||
- File: Resources\en.json
|
||||
Preview: "{ 'common.status.ready': 'Ready', 'common.cancel': 'Cancel', 'common.error': 'Error:', 'common.copy': 'Copy', 'common.status.error': 'Error', 'p..."
|
||||
- File: Services\AuthService.cs
|
||||
Symbols: [AuthService]
|
||||
Preview: "using AuthorBuddy.Web.Data; using LiteDB; namespace AuthorBuddy.Web.Services; public class AuthService : IAuthService { private readonly ILiteDataba..."
|
||||
- File: Services\CustomAuthStateProvider.cs
|
||||
Symbols: [CustomAuthStateProvider]
|
||||
Preview: "using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; namespace AuthorBuddy.Web.Services; public class CustomAuthStatePro..."
|
||||
- File: Services\FileScannerService.cs
|
||||
Symbols: [FileScannerService]
|
||||
Preview: "using AuthorBuddy.Web.Data; using LiteDB; namespace AuthorBuddy.Web.Services; public class FileScannerService : IFileScannerService { private readon..."
|
||||
- File: Services\IAuthService.cs
|
||||
Symbols: [IAuthService]
|
||||
Preview: "using AuthorBuddy.Web.Data; namespace AuthorBuddy.Web.Services; public interface IAuthService { Task<bool> LoginAsync(string username, string passwo..."
|
||||
- File: Services\IFileScannerService.cs
|
||||
Symbols: [IFileScannerService]
|
||||
Preview: "namespace AuthorBuddy.Web.Services; public interface IFileScannerService { Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<str..."
|
||||
- File: Services\ILocalizationService.cs
|
||||
Symbols: [ILocalizationService]
|
||||
Preview: "namespace AuthorBuddy.Web.Services; public interface ILocalizationService { string this[string key] { get; } string Get(string key); Task InitAs..."
|
||||
- File: Services\IOllamaService.cs
|
||||
Symbols: [IOllamaService]
|
||||
Preview: " using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IOllamaService { Task<IEnumerable<LLM_Model>> GetLocalModelsAsyn..."
|
||||
- File: Services\IProjectService.cs
|
||||
Symbols: [IProjectService]
|
||||
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IProjectService { Task<int> CreateNewProjectAsync(string projectN..."
|
||||
- File: Services\IRagService.cs
|
||||
Symbols: [IRagServi, RagSearchResult]
|
||||
Preview: "namespace AuthorBuddy.Web.Services; public class RagSearchResult { public string Text { get; set; } = string.Empty; public string FilePath { get; ..."
|
||||
- File: Services\ISettingsService.cs
|
||||
Symbols: [ISettingsService]
|
||||
Preview: "using AuthorBuddy.Web.Data; namespace AuthorBuddy.Web.Services; public interface ISettingsService { Task<string?> GetOllamaUrlAsync(); Task<string..."
|
||||
- File: Services\IThemeService.cs
|
||||
Preview: "namespace AuthorBuddy.Web.Services; public interface IThemeService { Task ApplyTheme(string theme); } "
|
||||
Symbols: [IThemeService]
|
||||
Preview: "namespace AuthorBuddy.Web.Services; public interface IThemeService { Task ApplyTheme(string theme); string Theme { get; } } "
|
||||
- File: Services\IWikipediaService.cs
|
||||
Symbols: [IWikipediaService]
|
||||
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IWikipediaService { Task<List<WikipediaResult>> SearchAsync(strin..."
|
||||
- File: Services\LocalizationService.cs
|
||||
Symbols: [LocalizationService]
|
||||
Preview: "using System.Text.Json; namespace AuthorBuddy.Web.Services; public class LocalizationService : ILocalizationService { private readonly ISettingsServ..."
|
||||
- File: Services\OllamaService.cs
|
||||
Symbols: [OllamaService]
|
||||
Preview: "using AuthorBuddy.Web.Models; using System.Text.Json; using static System.Net.Mime.MediaTypeNames; namespace AuthorBuddy.Web.Services; public class Ol..."
|
||||
- File: Services\ProjectService.cs
|
||||
Symbols: [ProjectService]
|
||||
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using LiteDB; namespace AuthorBuddy.Web.Services; public class ProjectService : IProjectServ..."
|
||||
- File: Services\RagService.cs
|
||||
Symbols: [RagService]
|
||||
Preview: "using AuthorBuddy.Web.Data; using LiteDB; using System.Security.Cryptography; using System.Text; namespace AuthorBuddy.Web.Services; public class RagS..."
|
||||
- File: Services\SettingsService.cs
|
||||
Symbols: [SettingsService]
|
||||
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using LiteDB; namespace AuthorBuddy.Web.Services; public class SettingsService : ISettingsSe..."
|
||||
- File: Services\ThemeService.cs
|
||||
Preview: "using Microsoft.JSInterop; namespace AuthorBuddy.Web.Services; public class ThemeService : IThemeService { private readonly IJSRuntime _js; public..."
|
||||
Symbols: [ThemeService]
|
||||
Preview: "using Microsoft.JSInterop; using System.Reflection.Metadata.Ecma335; namespace AuthorBuddy.Web.Services; public class ThemeService : IThemeService { ..."
|
||||
- File: Services\TotpHelper.cs
|
||||
Symbols: [TotpHelper]
|
||||
Preview: "using System.Security.Cryptography; namespace AuthorBuddy.Web.Services; public static class TotpHelper { private const int TotpSize = 6; private c..."
|
||||
- File: Services\WikipediaService.cs
|
||||
Symbols: [WikipediaService]
|
||||
Preview: "using AuthorBuddy.Web.Models; using System.Text.Json; using System.Web; namespace AuthorBuddy.Web.Services; public class WikipediaService : IWikipedia..."
|
||||
- File: Components\Layout\ReconnectModal.razor.js
|
||||
Preview: "// Set up event handlers const reconnectModal = document.getElementById('components-reconnect-modal'); reconnectModal.addEventListener('components-rec..."
|
||||
|
|
|
|||
|
|
@ -3,29 +3,68 @@
|
|||
"WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ithemeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ithemeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\userentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\userentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\assets\\logo.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:assets\\logo.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\redirecttologin.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\redirecttologin.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\login.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\login.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -34,14 +73,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -58,10 +89,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
|
|
@ -74,10 +101,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
|
|
@ -137,183 +160,103 @@
|
|||
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "UserEntity.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\UserEntity.cs",
|
||||
"RelativeDocumentMoniker": "Data\\UserEntity.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\UserEntity.cs",
|
||||
"RelativeToolTip": "Data\\UserEntity.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAIAAAAMAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-24T04:52:42.227Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "OllamaAssistant.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ViewState": "AgIAAAkAAAAAAAAAAAAAABEAAAARAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-20T05:14:39.037Z",
|
||||
"EditorCaption": ""
|
||||
"DocumentIndex": 5,
|
||||
"Title": "A7405018.jpg",
|
||||
"DocumentMoniker": "C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg",
|
||||
"ToolTip": "C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
|
||||
"WhenOpened": "2026-05-23T05:52:56.265Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "MainLayout.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor*",
|
||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor*",
|
||||
"ViewState": "AgIAAMkAAAAAAAAAAAAQwOcAAAARAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "OllamaSettings.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||
"ViewState": "AgIAAAYAAAAAAAAAAAAkwBQAAAASAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:39:46.179Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 17,
|
||||
"Title": "AppDbContext.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"Title": "FileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:02:53.46Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "IOllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeToolTip": "Services\\IOllamaService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T07:20:19.212Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeDocumentMoniker": "Program.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs*",
|
||||
"RelativeToolTip": "Program.cs*",
|
||||
"ViewState": "AgIAABgAAAAAAAAAAAAAADAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-20T04:07:21.54Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "TotpHelper.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeDocumentMoniker": "Services\\TotpHelper.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeToolTip": "Services\\TotpHelper.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-21T08:20:49.461Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 12,
|
||||
"Title": "Project.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeDocumentMoniker": "Models\\Project.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeToolTip": "Models\\Project.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-15T15:57:10.2Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "Settings.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
||||
"ViewState": "AgIAAAwAAAAAAAAAAAAAAIYAAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "SettingsService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
||||
"RelativeToolTip": "Services\\SettingsService.cs",
|
||||
"ViewState": "AgIAAEUBAAAAAAAAAAAQwFwBAAAAAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAAMBAAAAAAAAAAAAABsBAAApAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:05:12.928Z"
|
||||
"WhenOpened": "2026-05-21T17:37:24.777Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"Title": "OllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||
"ViewState": "AgIAAFkAAAAAAAAAAAAqwGsAAAAeAAAAAAAAAA==",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "IThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IThemeService.cs",
|
||||
"RelativeToolTip": "Services\\IThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAgAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||
"WhenOpened": "2026-05-21T17:32:01.784Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 13,
|
||||
"Title": "RagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeToolTip": "Services\\RagService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||
"DocumentIndex": 10,
|
||||
"Title": "RedirectToLogin.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\RedirectToLogin.razor",
|
||||
"RelativeDocumentMoniker": "Components\\RedirectToLogin.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\RedirectToLogin.razor",
|
||||
"RelativeToolTip": "Components\\RedirectToLogin.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-21T16:31:16.612Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"DocumentIndex": 6,
|
||||
"Title": "OllamaAssistant.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAGgAAAAMAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-20T05:14:39.037Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "MainLayout.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
||||
"ViewState": "AgIAAB4BAAAAAAAAAAApwDQBAAApAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:04:36.444Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "ISettingsService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||
"RelativeToolTip": "Services\\ISettingsService.cs",
|
||||
"ViewState": "AgIAABoAAAAAAAAAAAA8wCoAAAAPAAAAAAAAAA==",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAA9wC4AAAAZAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:21:26.951Z"
|
||||
"WhenOpened": "2026-05-21T16:35:36.655Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 14,
|
||||
"DocumentIndex": 3,
|
||||
"Title": "IRagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IRagService.cs",
|
||||
|
|
@ -325,7 +268,161 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"DocumentIndex": 13,
|
||||
"Title": "Login.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Login.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Login.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-21T08:47:41.996Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "ThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeToolTip": "Services\\ThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAAdAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:35:33.991Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeDocumentMoniker": "Program.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeToolTip": "Program.cs",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAAAABIAAAAsAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-20T04:07:21.54Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 12,
|
||||
"Title": "OllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||
"ViewState": "AgIAAGEAAAAAAAAAAAAcwHsAAAAVAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "logo.jpg",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Assets\\logo.jpg",
|
||||
"RelativeDocumentMoniker": "Assets\\logo.jpg",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Assets\\logo.jpg",
|
||||
"RelativeToolTip": "Assets\\logo.jpg",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
|
||||
"WhenOpened": "2026-05-21T17:15:10.852Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 16,
|
||||
"Title": "OllamaSettings.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||
"ViewState": "AgIAAAYAAAAAAAAAAAAkwBQAAAASAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:39:46.179Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 24,
|
||||
"Title": "AppDbContext.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 19,
|
||||
"Title": "FileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:02:53.46Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 17,
|
||||
"Title": "IOllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeToolTip": "Services\\IOllamaService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T07:20:19.212Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 14,
|
||||
"Title": "TotpHelper.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeDocumentMoniker": "Services\\TotpHelper.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeToolTip": "Services\\TotpHelper.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-21T08:20:49.461Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 20,
|
||||
"Title": "Project.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeDocumentMoniker": "Models\\Project.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeToolTip": "Models\\Project.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-15T15:57:10.2Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 15,
|
||||
"Title": "Settings.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
||||
"ViewState": "AgIAAAwAAAAAAAAAAAAAAIYAAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 21,
|
||||
"Title": "RagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeToolTip": "Services\\RagService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 18,
|
||||
"Title": "ProjectService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
|
||||
|
|
@ -337,7 +434,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 16,
|
||||
"DocumentIndex": 23,
|
||||
"Title": "NavMenu.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
||||
|
|
@ -349,7 +446,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 15,
|
||||
"DocumentIndex": 22,
|
||||
"Title": "Editor.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Editor.razor",
|
||||
|
|
@ -357,24 +454,11 @@
|
|||
"RelativeToolTip": "Components\\Pages\\Editor.razor",
|
||||
"ViewState": "AgIAAAoAAACA6NuCpTYvwKAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
||||
"EditorCaption": ""
|
||||
"WhenOpened": "2026-05-16T13:01:59.743Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 18,
|
||||
"Title": "ThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeToolTip": "Services\\ThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:35:33.991Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 19,
|
||||
"DocumentIndex": 25,
|
||||
"Title": "App.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
|
||||
"RelativeDocumentMoniker": "Components\\App.razor",
|
||||
|
|
@ -386,7 +470,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 22,
|
||||
"DocumentIndex": 28,
|
||||
"Title": "Models.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Models.razor",
|
||||
|
|
@ -398,7 +482,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 20,
|
||||
"DocumentIndex": 26,
|
||||
"Title": "LLM_Model.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
|
||||
"RelativeDocumentMoniker": "Models\\LLM_Model.cs",
|
||||
|
|
@ -410,7 +494,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 21,
|
||||
"DocumentIndex": 27,
|
||||
"Title": "ModelStatus.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
|
||||
"RelativeDocumentMoniker": "Models\\ModelStatus.cs",
|
||||
|
|
@ -422,7 +506,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 25,
|
||||
"DocumentIndex": 31,
|
||||
"Title": "MainLayout.razor.css",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor.css",
|
||||
|
|
@ -434,7 +518,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 23,
|
||||
"DocumentIndex": 29,
|
||||
"Title": "IFileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
||||
|
|
@ -446,7 +530,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 24,
|
||||
"DocumentIndex": 30,
|
||||
"Title": "bootstrap-utilities.css",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||
|
|
@ -458,7 +542,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 27,
|
||||
"DocumentIndex": 33,
|
||||
"Title": "ProjectEntity.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
||||
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
||||
|
|
@ -470,7 +554,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 26,
|
||||
"DocumentIndex": 32,
|
||||
"Title": "IProjectService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
||||
|
|
@ -482,7 +566,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 28,
|
||||
"DocumentIndex": 34,
|
||||
"Title": "AuthorBuddy.Web.csproj",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj",
|
||||
"RelativeDocumentMoniker": "AuthorBuddy.Web.csproj",
|
||||
|
|
@ -494,7 +578,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 29,
|
||||
"DocumentIndex": 35,
|
||||
"Title": "appsettings.json",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json",
|
||||
"RelativeDocumentMoniker": "appsettings.json",
|
||||
|
|
@ -503,6 +587,10 @@
|
|||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
||||
"WhenOpened": "2026-05-14T10:14:25.605Z"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,57 @@
|
|||
"Version": 1,
|
||||
"WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ithemeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ithemeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\userentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\userentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\assets\\logo.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:assets\\logo.jpg||{58961B49-13E0-48C0-9258-13CBC4D40279}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\redirecttologin.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\redirecttologin.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\login.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\login.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
|
|
@ -18,18 +61,10 @@
|
|||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\totphelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\ollamaassistant.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -38,14 +73,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -62,10 +89,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
|
|
@ -78,10 +101,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
|
|
@ -140,197 +159,104 @@
|
|||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "Login.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Login.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Login.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-21T08:47:41.996Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "MainLayout.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
||||
"ViewState": "AgIAAI0AAAAAAAAAAAAAAHIBAAAgAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeDocumentMoniker": "Program.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeToolTip": "Program.cs",
|
||||
"ViewState": "AgIAAAsAAAAAAAAAAAApwB8AAAAeAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-20T04:07:21.54Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "OllamaSettings.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||
"ViewState": "AgIAAAYAAAAAAAAAAAAkwBQAAAASAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:39:46.179Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 18,
|
||||
"Title": "AppDbContext.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 12,
|
||||
"Title": "FileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:02:53.46Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "IOllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeToolTip": "Services\\IOllamaService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T07:20:19.212Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "OllamaAssistant.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ViewState": "AgIAAAkAAAAAAAAAAAAAABEAAAARAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-20T05:14:39.037Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "TotpHelper.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeDocumentMoniker": "Services\\TotpHelper.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeToolTip": "Services\\TotpHelper.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Title": "UserEntity.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\UserEntity.cs",
|
||||
"RelativeDocumentMoniker": "Data\\UserEntity.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\UserEntity.cs",
|
||||
"RelativeToolTip": "Data\\UserEntity.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAIAAAAMAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-21T08:20:49.461Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 13,
|
||||
"Title": "Project.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeDocumentMoniker": "Models\\Project.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeToolTip": "Models\\Project.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-15T15:57:10.2Z"
|
||||
"WhenOpened": "2026-05-24T04:52:42.227Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"Title": "Settings.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
||||
"ViewState": "AgIAAAwAAAAAAAAAAAAAAIYAAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||
"Title": "A7405018.jpg",
|
||||
"DocumentMoniker": "C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg",
|
||||
"ToolTip": "C:\\Users\\HP\\Desktop\\Website\\A7405018.jpg",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
|
||||
"WhenOpened": "2026-05-23T05:52:56.265Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"DocumentIndex": 0,
|
||||
"Title": "SettingsService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
||||
"RelativeToolTip": "Services\\SettingsService.cs",
|
||||
"ViewState": "AgIAAEUBAAAAAAAAAAAQwFwBAAAAAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAO4AAAAAAAAAAAAqwBsBAAApAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:05:12.928Z"
|
||||
"WhenOpened": "2026-05-21T17:37:24.777Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "OllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||
"ViewState": "AgIAAFkAAAAAAAAAAAAqwGsAAAAeAAAAAAAAAA==",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "IThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IThemeService.cs",
|
||||
"RelativeToolTip": "Services\\IThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAgAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 14,
|
||||
"Title": "RagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeToolTip": "Services\\RagService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||
"WhenOpened": "2026-05-21T17:32:01.784Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"Title": "RedirectToLogin.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\RedirectToLogin.razor",
|
||||
"RelativeDocumentMoniker": "Components\\RedirectToLogin.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\RedirectToLogin.razor",
|
||||
"RelativeToolTip": "Components\\RedirectToLogin.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-21T16:31:16.612Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "OllamaAssistant.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\OllamaAssistant.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\OllamaAssistant.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAGgAAAAMAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-20T05:14:39.037Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "MainLayout.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
||||
"ViewState": "AgIAAB4BAAAAAAAAAAApwDQBAAApAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:04:36.444Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "ISettingsService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||
"RelativeToolTip": "Services\\ISettingsService.cs",
|
||||
"ViewState": "AgIAABoAAAAAAAAAAAA8wCoAAAAPAAAAAAAAAA==",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAA9wC4AAAAZAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:21:26.951Z"
|
||||
"WhenOpened": "2026-05-21T16:35:36.655Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 15,
|
||||
"DocumentIndex": 3,
|
||||
"Title": "IRagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IRagService.cs",
|
||||
|
|
@ -340,9 +266,163 @@
|
|||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-18T15:37:44.565Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 13,
|
||||
"Title": "Login.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Login.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Login.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Login.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-21T08:47:41.996Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "ThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeToolTip": "Services\\ThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAAdAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:35:33.991Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeDocumentMoniker": "Program.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||
"RelativeToolTip": "Program.cs",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAAAABIAAAAsAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-20T04:07:21.54Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 12,
|
||||
"Title": "OllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||
"ViewState": "AgIAAGEAAAAAAAAAAAAcwHsAAAAVAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "logo.jpg",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Assets\\logo.jpg",
|
||||
"RelativeDocumentMoniker": "Assets\\logo.jpg",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Assets\\logo.jpg",
|
||||
"RelativeToolTip": "Assets\\logo.jpg",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
|
||||
"WhenOpened": "2026-05-21T17:15:10.852Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 16,
|
||||
"Title": "OllamaSettings.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||
"ViewState": "AgIAAAYAAAAAAAAAAAAkwBQAAAASAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:39:46.179Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 24,
|
||||
"Title": "AppDbContext.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 19,
|
||||
"Title": "FileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T06:02:53.46Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 17,
|
||||
"Title": "IOllamaService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
|
||||
"RelativeToolTip": "Services\\IOllamaService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T07:20:19.212Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 14,
|
||||
"Title": "TotpHelper.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeDocumentMoniker": "Services\\TotpHelper.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\TotpHelper.cs",
|
||||
"RelativeToolTip": "Services\\TotpHelper.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-21T08:20:49.461Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 20,
|
||||
"Title": "Project.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeDocumentMoniker": "Models\\Project.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
|
||||
"RelativeToolTip": "Models\\Project.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-15T15:57:10.2Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 15,
|
||||
"Title": "Settings.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
||||
"ViewState": "AgIAAAwAAAAAAAAAAAAAAIYAAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 21,
|
||||
"Title": "RagService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||
"RelativeToolTip": "Services\\RagService.cs",
|
||||
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 18,
|
||||
"Title": "ProjectService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
|
||||
|
|
@ -354,7 +434,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 17,
|
||||
"DocumentIndex": 23,
|
||||
"Title": "NavMenu.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
||||
|
|
@ -366,7 +446,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 16,
|
||||
"DocumentIndex": 22,
|
||||
"Title": "Editor.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Editor.razor",
|
||||
|
|
@ -374,24 +454,11 @@
|
|||
"RelativeToolTip": "Components\\Pages\\Editor.razor",
|
||||
"ViewState": "AgIAAAoAAACA6NuCpTYvwKAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
||||
"EditorCaption": ""
|
||||
"WhenOpened": "2026-05-16T13:01:59.743Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 19,
|
||||
"Title": "ThemeService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
|
||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
||||
"RelativeToolTip": "Services\\ThemeService.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-05-16T13:35:33.991Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 20,
|
||||
"DocumentIndex": 25,
|
||||
"Title": "App.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
|
||||
"RelativeDocumentMoniker": "Components\\App.razor",
|
||||
|
|
@ -403,7 +470,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 23,
|
||||
"DocumentIndex": 28,
|
||||
"Title": "Models.razor",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
|
||||
"RelativeDocumentMoniker": "Components\\Pages\\Models.razor",
|
||||
|
|
@ -415,7 +482,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 21,
|
||||
"DocumentIndex": 26,
|
||||
"Title": "LLM_Model.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
|
||||
"RelativeDocumentMoniker": "Models\\LLM_Model.cs",
|
||||
|
|
@ -427,7 +494,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 22,
|
||||
"DocumentIndex": 27,
|
||||
"Title": "ModelStatus.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
|
||||
"RelativeDocumentMoniker": "Models\\ModelStatus.cs",
|
||||
|
|
@ -439,7 +506,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 26,
|
||||
"DocumentIndex": 31,
|
||||
"Title": "MainLayout.razor.css",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
|
||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor.css",
|
||||
|
|
@ -451,7 +518,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 24,
|
||||
"DocumentIndex": 29,
|
||||
"Title": "IFileScannerService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
||||
|
|
@ -463,7 +530,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 25,
|
||||
"DocumentIndex": 30,
|
||||
"Title": "bootstrap-utilities.css",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||
|
|
@ -475,7 +542,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 28,
|
||||
"DocumentIndex": 33,
|
||||
"Title": "ProjectEntity.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
||||
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
||||
|
|
@ -487,7 +554,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 27,
|
||||
"DocumentIndex": 32,
|
||||
"Title": "IProjectService.cs",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
||||
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
||||
|
|
@ -499,7 +566,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 29,
|
||||
"DocumentIndex": 34,
|
||||
"Title": "AuthorBuddy.Web.csproj",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj",
|
||||
"RelativeDocumentMoniker": "AuthorBuddy.Web.csproj",
|
||||
|
|
@ -511,7 +578,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 30,
|
||||
"DocumentIndex": 35,
|
||||
"Title": "appsettings.json",
|
||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json",
|
||||
"RelativeDocumentMoniker": "appsettings.json",
|
||||
|
|
@ -520,6 +587,10 @@
|
|||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
||||
"WhenOpened": "2026-05-14T10:14:25.605Z"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
BIN
Assets/logo.jpg
Normal file
BIN
Assets/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 181 KiB |
BIN
Assets/splash.jpg
Normal file
BIN
Assets/splash.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
|
|
@ -12,4 +12,8 @@
|
|||
<PackageReference Include="LiteDB" Version="5.0.21" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Resources\**" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -6,75 +6,101 @@
|
|||
@inject OllamaSettings OllamaSettings
|
||||
@inject IAuthService AuthService
|
||||
@inject CustomAuthStateProvider AuthStateProvider
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
<div class="page">
|
||||
@if (_isLoading)
|
||||
{
|
||||
<div class="splash-screen">
|
||||
<div class="splash-bg" style="background-image:url('/Assets/splash.jpg')"></div>
|
||||
<div class="splash-content">
|
||||
<div class="splash-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<div class="splash-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="page">
|
||||
<div class="main-content">
|
||||
@if (_isAuthenticated)
|
||||
{
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<div class="nav-section">
|
||||
<button class="nav-section-header" @onclick='() => ToggleSection("file")'>
|
||||
<span class="nav-icon">@(activeSection == "file" ? "▼" : "▶")</span>
|
||||
@T("Datei", "File")
|
||||
@Loc["nav.menu.file"]
|
||||
</button>
|
||||
@if (activeSection == "file")
|
||||
{
|
||||
<div class="nav-section-body">
|
||||
<button class="nav-item" @onclick="CreateNewProject">@T("Neues Projekt", "New project")</button>
|
||||
<button class="nav-item" @onclick="OpenEditor">@T("Editor \u00f6ffnen", "Open editor")</button>
|
||||
<button class="nav-item" @onclick="CreateNewProject">@Loc["nav.menu.file.new_project"]</button>
|
||||
<button class="nav-item" @onclick="OpenEditor">@Loc["nav.menu.file.open_editor"]</button>
|
||||
<div class="nav-separator"></div>
|
||||
<button class="nav-item" @onclick="ExitApp">@T("Beenden", "Exit")</button>
|
||||
<button class="nav-item" @onclick="ExitApp">@Loc["nav.menu.file.exit"]</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="nav-section">
|
||||
<button class="nav-section-header" @onclick='() => ToggleSection("extras")'>
|
||||
<span class="nav-icon">@(activeSection == "extras" ? "▼" : "▶")</span>
|
||||
@T("Extras", "Extras")
|
||||
@Loc["nav.menu.extras"]
|
||||
</button>
|
||||
@if (activeSection == "extras")
|
||||
{
|
||||
<div class="nav-section-body">
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/settings")'>@T("Einstellungen", "Settings")</button>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/models")'>@T("Modelle verwalten", "Manage models")</button>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/assistant")'>@T("Assistent", "Assistant")</button>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/settings")'>@Loc["nav.menu.extras.settings"]</button>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/models")'>@Loc["nav.menu.extras.manage_models"]</button>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/assistant")'>@Loc["nav.menu.extras.assistant"]</button>
|
||||
@if (_currentUserRole == UserRole.Administrator)
|
||||
{
|
||||
<div class="nav-separator"></div>
|
||||
<button class="nav-item" @onclick='() => NavigateTo("/user-management")'>@Loc["nav.menu.extras.user_management"]</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="nav-section">
|
||||
<button class="nav-section-header" @onclick='() => ToggleSection("projects")'>
|
||||
<span class="nav-icon">@(activeSection == "projects" ? "▼" : "▶")</span>
|
||||
@T("Projekte", "Projects")
|
||||
@Loc["nav.menu.projects"]
|
||||
</button>
|
||||
@if (activeSection == "projects")
|
||||
{
|
||||
<div class="nav-section-body">
|
||||
<button class="nav-item nav-item-toggle" @onclick='() => showProjectList = !showProjectList'>
|
||||
<span class="nav-icon">@(showProjectList ? "▼" : "▶")</span>
|
||||
@T("Liste vorhandener Projekte", "List existing projects")
|
||||
@Loc["nav.projects.list_title"]
|
||||
</button>
|
||||
@if (showProjectList)
|
||||
{
|
||||
<div class="nav-sublist">
|
||||
@if (projects == null)
|
||||
{
|
||||
<span class="nav-hint">@T("Lade Projekte...", "Loading projects...")</span>
|
||||
<span class="nav-hint">@Loc["nav.projects.loading"]</span>
|
||||
}
|
||||
else if (projects.Count == 0)
|
||||
{
|
||||
<span class="nav-hint">@T("Keine Projekte vorhanden.", "No projects available.")</span>
|
||||
<span class="nav-hint">@Loc["nav.projects.empty"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var p in projects)
|
||||
{
|
||||
<button class="nav-item nav-item-sub @(p.Id == currentProjectId ? "active" : "")" @onclick='() => SelectProject(p)'>@p.Name</button>
|
||||
<div class="nav-item nav-item-sub @(p.Id == currentProjectId ? "active" : "")">
|
||||
<button class="nav-item-text" @onclick='() => SelectProject(p)'>@p.Name</button>
|
||||
<button class="nav-item-icon" @onclick='() => BeginCopyProject(p)' title="@Loc["nav.projects.copy"]">⧉</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="nav-separator"></div>
|
||||
<button class="nav-item" @onclick="CreateNewProject">@T("Projekt erstellen", "Create project")</button>
|
||||
<button class="nav-item" @onclick="CreateNewProject">@Loc["nav.projects.create"]</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -82,9 +108,9 @@
|
|||
{
|
||||
<div class="nav-section nav-section-open">
|
||||
<div class="nav-section-header">
|
||||
<span>@T("Projektdateien", "Project files")</span>
|
||||
<span>@Loc["nav.projects.files"]</span>
|
||||
<span class="nav-header-actions">
|
||||
<button class="nav-item-icon" @onclick="RefreshFileTree" title="@T("Dateibaum aktualisieren", "Refresh file tree")">↻</button>
|
||||
<button class="nav-item-icon" @onclick="RefreshFileTree" title="@Loc["nav.projects.refresh_tree"]">↻</button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="nav-section-body">
|
||||
|
|
@ -96,11 +122,11 @@
|
|||
<span class="tree-name">@item.Name</span>
|
||||
@if (item.IsDirectory)
|
||||
{
|
||||
<button class="tree-rename" @onclick="() => BeginNewFile(item)" @onclick:stopPropagation title="@T("Neue Datei", "New file")">+</button>
|
||||
<button class="tree-rename" @onclick="() => BeginNewFile(item)" @onclick:stopPropagation title="@Loc["nav.projects.file.new"]">+</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="tree-rename" @onclick="() => BeginRename(item)" @onclick:stopPropagation title="@T("Umbenennen", "Rename")">✎</button>
|
||||
<button class="tree-rename" @onclick="() => BeginRename(item)" @onclick:stopPropagation title="@Loc["nav.projects.file.rename"]">✎</button>
|
||||
}
|
||||
</div>
|
||||
@foreach (var child in item.Children)
|
||||
|
|
@ -109,7 +135,7 @@
|
|||
@onclick="() => OpenFile(child)">
|
||||
<span class="tree-icon">📄</span>
|
||||
<span class="tree-name">@child.Name</span>
|
||||
<button class="tree-rename" @onclick="() => BeginRename(child)" @onclick:stopPropagation title="@T("Umbenennen", "Rename")">✎</button>
|
||||
<button class="tree-rename" @onclick="() => BeginRename(child)" @onclick:stopPropagation title="@Loc["nav.projects.file.rename"]">✎</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
@ -121,16 +147,39 @@
|
|||
{
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-title">@T("Datei umbenennen", "Rename file")</div>
|
||||
<div class="modal-title">@Loc["nav.rename.title"]</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>@T("Neuer Name", "New name")</label>
|
||||
<input @bind="renameNewName" placeholder="@T("neuer_name.md", "new_name.md")" />
|
||||
<label>@Loc["nav.rename.label.new_name"]</label>
|
||||
<input @bind="renameNewName" placeholder="@Loc["nav.rename.placeholder"]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button @onclick="CancelRename">@T("Abbrechen", "Cancel")</button>
|
||||
<button @onclick="ConfirmRename" disabled="@(string.IsNullOrWhiteSpace(renameNewName))" class="primary">@T("Umbenennen", "Rename")</button>
|
||||
<button @onclick="CancelRename">@Loc["common.cancel"]</button>
|
||||
<button @onclick="ConfirmRename" disabled="@(string.IsNullOrWhiteSpace(renameNewName))" class="primary">@Loc["nav.rename.button.confirm"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (showCopyProjectDialog)
|
||||
{
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-title">@Loc["nav.copy_project.title"]</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>@Loc["nav.copy_project.label.name"]</label>
|
||||
<input @bind="copyProjectName" placeholder="@Loc["nav.copy_project.placeholder.name"]" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>@Loc["nav.copy_project.label.path"]</label>
|
||||
<input @bind="copyProjectPath" placeholder="@Loc["nav.copy_project.placeholder.path"]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button @onclick="CancelCopyProject">@Loc["common.cancel"]</button>
|
||||
<button @onclick="ConfirmCopyProject" disabled="@(string.IsNullOrWhiteSpace(copyProjectName) || string.IsNullOrWhiteSpace(copyProjectPath))" class="primary">@Loc["nav.copy_project.button.copy"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -140,16 +189,16 @@
|
|||
{
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-title">@T("Neue Datei", "New file")</div>
|
||||
<div class="modal-title">@Loc["nav.newfile.title"]</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>@T("Dateiname", "Filename")</label>
|
||||
<input @bind="newFileName" placeholder="@T("meine_datei.md", "my_file.md")" />
|
||||
<label>@Loc["nav.newfile.label.filename"]</label>
|
||||
<input @bind="newFileName" placeholder="@Loc["nav.newfile.placeholder"]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button @onclick="CancelNewFile">@T("Abbrechen", "Cancel")</button>
|
||||
<button @onclick="ConfirmNewFile" disabled="@(string.IsNullOrWhiteSpace(newFileName))" class="primary">@T("Erstellen", "Create")</button>
|
||||
<button @onclick="CancelNewFile">@Loc["common.cancel"]</button>
|
||||
<button @onclick="ConfirmNewFile" disabled="@(string.IsNullOrWhiteSpace(newFileName))" class="primary">@Loc["nav.newfile.button.create"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -159,15 +208,18 @@
|
|||
{
|
||||
<div class="nav-section" style="border-top:1px solid var(--border-color);margin-top:8px;padding-top:4px;">
|
||||
<div class="nav-section-header" style="cursor:default;">
|
||||
<span style="font-size:11px;font-weight:normal;">@T("Angemeldet als:", "Logged in as:") @_username</span>
|
||||
<span style="font-size:11px;font-weight:normal;">@Loc["nav.user.logged_in_as"] @_username</span>
|
||||
</div>
|
||||
<div class="nav-section-body">
|
||||
<button class="nav-item" @onclick="NavigateToSetup2FA">@T("2FA verwalten", "Manage 2FA")</button>
|
||||
<button class="nav-item" @onclick="Logout">@T("Abmelden", "Logout")</button>
|
||||
<button class="nav-item" @onclick="NavigateToSetup2FA">@Loc["nav.user.manage_2fa"]</button>
|
||||
<button class="nav-item" @onclick="Logout">@Loc["nav.user.logout"]</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="sidebar-spacer"></div>
|
||||
<button class="sidebar-info-btn" @onclick="ToggleInfoOverlay" title="Info">i</button>
|
||||
|
||||
</aside>
|
||||
}
|
||||
|
||||
|
|
@ -185,11 +237,33 @@
|
|||
}
|
||||
</footer>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (_showInfoOverlay)
|
||||
{
|
||||
<div class="splash-screen" @onclick="CloseInfoOverlay">
|
||||
<div class="splash-bg" style="background-image:url('/Assets/splash.jpg')"></div>
|
||||
<div class="splash-content info-content" @onclick:stopPropagation>
|
||||
<div class="splash-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<h1>Author Buddy</h1>
|
||||
<p class="info-version">Version 1.0</p>
|
||||
<p class="info-copyright">© 2026 Author Buddy. Alle Rechte vorbehalten.</p>
|
||||
<p class="info-homepage">
|
||||
<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>
|
||||
</p>
|
||||
<button class="info-close-btn" @onclick="CloseInfoOverlay">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string _username = string.Empty;
|
||||
private bool _isAuthenticated;
|
||||
private UserRole _currentUserRole;
|
||||
private bool _isLoading = true;
|
||||
private bool _showInfoOverlay;
|
||||
private string? activeSection;
|
||||
private bool showProjectList;
|
||||
private List<Project>? projects;
|
||||
|
|
@ -205,8 +279,10 @@
|
|||
private bool showNewFileDialog;
|
||||
private string newFileName = string.Empty;
|
||||
private FileTreeItem? newFileParentDir;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
private bool showCopyProjectDialog;
|
||||
private string copyProjectName = string.Empty;
|
||||
private string copyProjectPath = string.Empty;
|
||||
private Project? copyProjectSource;
|
||||
|
||||
[Inject]
|
||||
private NavigationManager Navigation { get; set; } = default!;
|
||||
|
|
@ -214,8 +290,8 @@
|
|||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await SettingsService.InitializeAsync();
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
statusText = T("Bereit", "Ready");
|
||||
await Loc.InitAsync();
|
||||
statusText = Loc["common.status.ready"];
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +300,7 @@
|
|||
var user = await AuthService.GetCurrentUserAsync();
|
||||
_username = user?.Name ?? string.Empty;
|
||||
_isAuthenticated = user != null;
|
||||
_currentUserRole = user?.Role ?? UserRole.Author;
|
||||
}
|
||||
|
||||
private async Task AutoLoadLastProject()
|
||||
|
|
@ -234,18 +311,20 @@
|
|||
var project = projects?.FirstOrDefault(p => p.Id == lastId.Value);
|
||||
if (project != null)
|
||||
{
|
||||
await SettingsService.InitializeAsync(lastId.Value);
|
||||
SettingsService.CurrentProjectId = project.Id;
|
||||
await SettingsService.InitializeAsync();
|
||||
await SelectProject(project);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
var themeChanged = OllamaSettings.Theme != ThemeService.Theme;
|
||||
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
var theme = OllamaSettings.Theme;
|
||||
if (!string.IsNullOrEmpty(theme))
|
||||
await ThemeService.ApplyTheme(theme);
|
||||
await ThemeService.ApplyTheme(OllamaSettings.Theme);
|
||||
|
||||
// Auto-login runs AFTER circuit establishment (correct scoped services)
|
||||
await LoadCurrentUser();
|
||||
|
|
@ -268,6 +347,8 @@
|
|||
await LoadProjectContext();
|
||||
await AutoLoadLastProject();
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -344,6 +425,62 @@
|
|||
Navigation.NavigateTo("/editor/newproject");
|
||||
}
|
||||
|
||||
private void BeginCopyProject(Project project)
|
||||
{
|
||||
copyProjectSource = project;
|
||||
copyProjectName = $"{project.Name} (Kopie)";
|
||||
copyProjectPath = project.RootPath + "_Kopie";
|
||||
showCopyProjectDialog = true;
|
||||
}
|
||||
|
||||
private void CancelCopyProject()
|
||||
{
|
||||
showCopyProjectDialog = false;
|
||||
copyProjectSource = null;
|
||||
copyProjectName = string.Empty;
|
||||
copyProjectPath = string.Empty;
|
||||
}
|
||||
|
||||
private async Task ConfirmCopyProject()
|
||||
{
|
||||
if (copyProjectSource == null || string.IsNullOrWhiteSpace(copyProjectName) || string.IsNullOrWhiteSpace(copyProjectPath))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var userId = (await AuthService.GetCurrentUserAsync())?.Id;
|
||||
if (userId == null) return;
|
||||
|
||||
statusText = $"{Loc["nav.status.project_copied"]} {copyProjectName}...";
|
||||
isBusy = true;
|
||||
StateHasChanged();
|
||||
|
||||
var newId = await ProjectService.CopyProjectAsync(copyProjectSource.Id, copyProjectName, copyProjectPath, userId.Value);
|
||||
await LoadProjects();
|
||||
|
||||
var newProject = projects?.FirstOrDefault(p => p.Id == newId);
|
||||
if (newProject != null)
|
||||
{
|
||||
await SelectProject(newProject);
|
||||
}
|
||||
|
||||
statusText = $"{Loc["nav.status.project_copied"]} {copyProjectName}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
isBusy = false;
|
||||
showCopyProjectDialog = false;
|
||||
copyProjectSource = null;
|
||||
copyProjectName = string.Empty;
|
||||
copyProjectPath = string.Empty;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenEditor()
|
||||
{
|
||||
activeSection = null;
|
||||
|
|
@ -356,6 +493,16 @@
|
|||
Navigation.NavigateTo(path);
|
||||
}
|
||||
|
||||
private void ToggleInfoOverlay()
|
||||
{
|
||||
_showInfoOverlay = !_showInfoOverlay;
|
||||
}
|
||||
|
||||
private void CloseInfoOverlay()
|
||||
{
|
||||
_showInfoOverlay = false;
|
||||
}
|
||||
|
||||
private void NavigateToSetup2FA()
|
||||
{
|
||||
activeSection = null;
|
||||
|
|
@ -413,7 +560,7 @@
|
|||
var newPath = Path.Combine(dir, renameNewName);
|
||||
if (File.Exists(newPath))
|
||||
{
|
||||
statusText = T("Datei existiert bereits.", "File already exists.");
|
||||
statusText = Loc["nav.error.file_exists"];
|
||||
return;
|
||||
}
|
||||
File.Move(renameTarget.FullPath, newPath);
|
||||
|
|
@ -421,11 +568,11 @@
|
|||
if (currentFilePath == renameTarget.FullPath)
|
||||
SettingsService.CurrentFilePath = newPath;
|
||||
|
||||
statusText = $"{T("Umbenannt zu:", "Renamed to:")} {renameNewName}";
|
||||
statusText = $"{Loc["nav.status.renamed_to"]} {renameNewName}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -462,15 +609,15 @@
|
|||
path += ".md";
|
||||
if (File.Exists(path))
|
||||
{
|
||||
statusText = T("Datei existiert bereits.", "File already exists.");
|
||||
statusText = Loc["nav.error.file_exists"];
|
||||
return;
|
||||
}
|
||||
File.WriteAllText(path, $"# {Path.GetFileNameWithoutExtension(path)}\n\n");
|
||||
statusText = $"{T("Erstellt:", "Created:")} {Path.GetFileName(path)}";
|
||||
statusText = $"{Loc["nav.status.created"]} {Path.GetFileName(path)}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,82 +1,143 @@
|
|||
@page "/editor"
|
||||
@page "/editor/{action}"
|
||||
@page "/editor/{action}/{projectId:int}"
|
||||
@using System.Threading
|
||||
@inject IOllamaService OllamaService
|
||||
@inject IProjectService ProjectService
|
||||
@inject IRagService RagService
|
||||
@inject ISettingsService SettingsService
|
||||
@inject IWikipediaService WikipediaService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
@implements IDisposable
|
||||
@rendermode InteractiveServer
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>@T("Editor - Author Buddy", "Editor - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.editor"]</PageTitle>
|
||||
|
||||
<div class="editor-page">
|
||||
<textarea class="editor-area" @bind="editorContent" placeholder="@T("Schreibe hier deinen Text...", "Write your text here...")"></textarea>
|
||||
<textarea class="editor-area"
|
||||
@oninput="OnContentChanged"
|
||||
value="@editorContent"
|
||||
placeholder="@Loc["editor.placeholder.content"]"></textarea>
|
||||
|
||||
<div class="editor-toolbar">
|
||||
<span style="flex: 1; font-size: 12px; color: var(--border-color);">
|
||||
<span style="flex: 1; font-size: 12px; color: var(--border-color); display:flex;align-items:center;gap:8px;">
|
||||
@if (_contentModified)
|
||||
{
|
||||
<span class="editor-modified-badge">●</span>
|
||||
}
|
||||
@statusText
|
||||
</span>
|
||||
@if (isChecking)
|
||||
{
|
||||
<progress value="@checkProgress" max="100"></progress>
|
||||
}
|
||||
<button @onclick="CheckStyle" disabled="@isChecking">@T("Stil pr\u00fcfen", "Check style")</button>
|
||||
<button @onclick="SpellCheck" disabled="@isChecking">@T("Rechtschreibung pr\u00fcfen", "Spell check")</button>
|
||||
<button @onclick="SaveCurrentFile" disabled="@(string.IsNullOrEmpty(currentFile))">@T("Speichern", "Save")</button>
|
||||
<button @onclick="ShowVersionDialog" disabled="@(string.IsNullOrEmpty(currentFile))">@T("Version", "Version")</button>
|
||||
<button @onclick="OpenAssistant">@T("Assistent", "Assistant")</button>
|
||||
<button @onclick="IndexProject" disabled="@isChecking">@T("Projekt indexieren", "Index project")</button>
|
||||
<button @onclick="CheckStyle" disabled="@isChecking">@Loc["editor.button.style_check"]</button>
|
||||
<button @onclick="SpellCheck" disabled="@isChecking">@Loc["editor.button.spell_check"]</button>
|
||||
<button @onclick="SaveCurrentFile" disabled="@(string.IsNullOrEmpty(currentFile))">@Loc["editor.button.save"]</button>
|
||||
<button @onclick="ShowVersionDialog" disabled="@(string.IsNullOrEmpty(currentFile))">@Loc["editor.version.button.save"]</button>
|
||||
<button @onclick="ShowVersionBrowser" disabled="@(string.IsNullOrEmpty(currentFile))">@Loc["editor.version.button.browse"]</button>
|
||||
<button @onclick="OpenAssistant">@Loc["editor.button.assistant"]</button>
|
||||
<button @onclick="IndexProject" disabled="@isChecking">@Loc["editor.button.index_project"]</button>
|
||||
</div>
|
||||
|
||||
@if (showVersionDialog)
|
||||
{
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-title">@T("Version speichern", "Save version")</div>
|
||||
<div class="modal-title">@Loc["editor.version.title"]</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>@T("Kommentar (optional)", "Comment (optional)")</label>
|
||||
<input @bind="versionComment" placeholder="@T("Was hat sich ge\u00e4ndert?", "What changed?")" />
|
||||
<label>@Loc["editor.version.label.comment"]</label>
|
||||
<input @bind="versionComment" placeholder="@Loc["editor.version.placeholder.comment"]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button @onclick="() => showVersionDialog = false">@T("Abbrechen", "Cancel")</button>
|
||||
<button @onclick="SaveVersioned" class="primary">@T("Version speichern", "Save version")</button>
|
||||
<button @onclick="() => showVersionDialog = false">@Loc["common.cancel"]</button>
|
||||
<button @onclick="SaveVersioned" class="primary">@Loc["editor.version.button.save"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="search-section">
|
||||
<input value="@searchQuery" @oninput="HandleSearchInput" placeholder="@T("Suchbegriff f\u00fcr Fakten-/Wikipedia-Recherche...", "Search term for fact/Wikipedia research...")"
|
||||
<input value="@searchQuery" @oninput="HandleSearchInput" placeholder="@Loc["editor.search.placeholder"]"
|
||||
disabled="@isChecking" />
|
||||
|
||||
<button @onclick="RagSearch" disabled=@buttonDisabled>@T("Fakten suchen (RAG)", "Search facts (RAG)")</button>
|
||||
<button @onclick="SearchWikipedia" disabled=@buttonDisabled>@T("Wikipedia-Recherche", "Wikipedia research")</button>
|
||||
<button @onclick="RagSearch" disabled=@buttonDisabled>@Loc["editor.button.search_rag"]</button>
|
||||
<button @onclick="SearchWikipedia" disabled=@buttonDisabled>@Loc["editor.button.search_wikipedia"]</button>
|
||||
</div>
|
||||
<div style="display:none">@searchQuery</div>
|
||||
|
||||
@if (showSpellDiff && !string.IsNullOrEmpty(correctedText))
|
||||
{
|
||||
<div class="results-area">
|
||||
<div class="diff-panel">
|
||||
<h4>@T("Rechtschreibpr\u00fcfung - \u00c4nderungen:", "Spell check - Changes:")</h4>
|
||||
<h4>@Loc["editor.spellcheck.heading"]</h4>
|
||||
<DiffView Original="@originalText" Corrected="@correctedText" />
|
||||
<div class="diff-actions">
|
||||
<button class="btn btn-primary" @onclick="ApplySpellCorrections">@Loc["editor.spellcheck.button.apply"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (showVersionDiff && _selectedVersion != null)
|
||||
{
|
||||
<div class="results-area">
|
||||
<div class="diff-panel">
|
||||
<h4>@Loc["editor.version.diff_title"] @_selectedVersion.Timestamp:dd.MM.yyyy HH:mm</h4>
|
||||
@if (!string.IsNullOrEmpty(_selectedVersion.Comment))
|
||||
{
|
||||
<p style="font-size:11px;color:var(--border-color);margin:0 0 8px 0;">@Loc["editor.version.label.comment"]: @_selectedVersion.Comment</p>
|
||||
}
|
||||
<DiffView Original="@editorContent" Corrected="@_versionDiffContent" />
|
||||
<div class="diff-actions">
|
||||
<button class="btn btn-primary" @onclick="() => RestoreVersion(_selectedVersion)">@Loc["editor.version.button.restore"]</button>
|
||||
<button class="btn btn-secondary" @onclick="CloseVersionBrowser">@Loc["common.cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (showVersionBrowser)
|
||||
{
|
||||
<div class="results-area">
|
||||
<h4>@Loc["editor.version.list_title"]</h4>
|
||||
@if (_versionList == null || _versionList.Count == 0)
|
||||
{
|
||||
<p>@Loc["editor.version.empty"]</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="version-list">
|
||||
@foreach (var v in _versionList)
|
||||
{
|
||||
<div class="version-item @(v == _selectedVersion ? "active" : "")">
|
||||
<div class="version-item-info">
|
||||
<span class="version-date">@v.Timestamp.ToString("dd.MM.yyyy HH:mm")</span>
|
||||
@if (!string.IsNullOrEmpty(v.Comment))
|
||||
{
|
||||
<span class="version-comment">@v.Comment</span>
|
||||
}
|
||||
</div>
|
||||
<div class="version-item-actions">
|
||||
<button class="btn btn-sm" @onclick="() => ShowVersionDiff(v)">@Loc["editor.version.button.diff"]</button>
|
||||
<button class="btn btn-sm btn-primary" @onclick="() => RestoreVersion(v)">@Loc["editor.version.button.restore"]</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<button class="btn btn-secondary" @onclick="CloseVersionBrowser">@Loc["common.cancel"]</button>
|
||||
</div>
|
||||
}
|
||||
else if (ragResults != null && ragResults.Count > 0)
|
||||
{
|
||||
<div class="results-area">
|
||||
<h4>@T("Gefundene Fakten (RAG):", "Found facts (RAG):")</h4>
|
||||
<h4>@Loc["editor.rag.heading"]</h4>
|
||||
@foreach (var r in ragResults)
|
||||
{
|
||||
<div class="fact-card">
|
||||
<div class="fact-similarity">@T("\u00c4hnlichkeit:", "Similarity:") @r.Similarity.ToString("P1")</div>
|
||||
<div class="fact-similarity">@Loc["editor.rag.label.similarity"] @r.Similarity.ToString("P1")</div>
|
||||
<div class="fact-path">@r.FilePath</div>
|
||||
<div class="fact-text">@r.Text</div>
|
||||
</div>
|
||||
|
|
@ -86,7 +147,7 @@
|
|||
else if (wikipediaResults != null && wikipediaResults.Count > 0)
|
||||
{
|
||||
<div class="results-area">
|
||||
<h4>@T("Wikipedia-Recherche:", "Wikipedia research:")</h4>
|
||||
<h4>@Loc["editor.wikipedia.heading"]</h4>
|
||||
@foreach (var r in wikipediaResults)
|
||||
{
|
||||
<div class="fact-card">
|
||||
|
|
@ -102,21 +163,21 @@
|
|||
<div class="fact-actions">
|
||||
<button @onclick="() => LoadFullArticle(r)" disabled="@(loadedArticles.ContainsKey(r.Url))">
|
||||
@(loadedArticles.ContainsKey(r.Url)
|
||||
? T("✓ Geladen", "✓ Loaded")
|
||||
: T("Vollst\u00e4ndigen Artikel laden", "Load full article"))
|
||||
? Loc["editor.wikipedia.status.loaded"]
|
||||
: Loc["editor.wikipedia.button.load"])
|
||||
</button>
|
||||
<button @onclick="() => SaveAsFact(r)" disabled="@(string.IsNullOrWhiteSpace(r.Extract) || currentProjectId == 0)">
|
||||
@T("Als Fakt speichern", "Save as fact")
|
||||
@Loc["editor.wikipedia.button.save_as_fact"]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(analysisResult))
|
||||
else if (!string.IsNullOrEmpty(analysisResult) && !showVersionBrowser)
|
||||
{
|
||||
<div class="results-area">
|
||||
<h4>@T("Ergebnis:", "Result:")</h4>
|
||||
<h4>@Loc["editor.result.heading"]</h4>
|
||||
<div class="result-text">@analysisResult</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -126,30 +187,26 @@
|
|||
{
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-title">@T("Neues Projekt erstellen", "Create new project")</div>
|
||||
<div class="modal-title">@Loc["editor.create_project.title"]</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>@T("Projektname", "Project name")</label>
|
||||
<input @bind="newProjectName" placeholder="@T("z.B. Mein Roman", "e.g. My novel")" />
|
||||
<label>@Loc["editor.create_project.label.name"]</label>
|
||||
<input @bind="newProjectName" placeholder="@Loc["editor.create_project.placeholder.name"]" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>@T("Projektpfad", "Project path")</label>
|
||||
<input @bind="newProjectPath" placeholder="@T("z.B. C:\\Projekte\\MeinRoman", "e.g. C:\\Projects\\MyNovel")" />
|
||||
<label>@Loc["editor.create_project.label.path"]</label>
|
||||
<input @bind="newProjectPath" placeholder="@Loc["editor.create_project.placeholder.path"]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button @onclick="CancelCreateProject">@T("Abbrechen", "Cancel")</button>
|
||||
<button @onclick="CreateProject" disabled="@(() => string.IsNullOrWhiteSpace(newProjectName) || string.IsNullOrWhiteSpace(newProjectPath))" class="primary">@T("Erstellen", "Create")</button>
|
||||
<button @onclick="CancelCreateProject">@Loc["common.cancel"]</button>
|
||||
<button @onclick="CreateProject" disabled="@(() => string.IsNullOrWhiteSpace(newProjectName) || string.IsNullOrWhiteSpace(newProjectPath))" class="primary">@Loc["editor.button.create"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
[Parameter]
|
||||
public string? Action { get; set; }
|
||||
|
||||
|
|
@ -179,12 +236,20 @@
|
|||
private string versionComment = string.Empty;
|
||||
private VersionEntry? latestVersion;
|
||||
|
||||
private Timer? _autosaveTimer;
|
||||
private string _lastSavedContent = string.Empty;
|
||||
private bool _contentModified;
|
||||
private bool showVersionBrowser;
|
||||
private bool showVersionDiff;
|
||||
private List<VersionEntry> _versionList = new();
|
||||
private VersionEntry? _selectedVersion;
|
||||
private string _versionDiffContent = string.Empty;
|
||||
|
||||
private record VersionEntry(string FilePath, DateTime Timestamp, string? Comment);
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
|
||||
|
|
@ -195,7 +260,8 @@
|
|||
{
|
||||
SettingsService.PendingAssistantOutput = null;
|
||||
editorContent = pendingOutput;
|
||||
statusText = T("Text aus Assistent \u00fcbernommen.", "Text imported from assistant.");
|
||||
_lastSavedContent = editorContent;
|
||||
statusText = Loc["editor.status.imported_from_assistant"];
|
||||
}
|
||||
|
||||
if (string.Equals(Action, "newproject", StringComparison.OrdinalIgnoreCase))
|
||||
|
|
@ -213,6 +279,41 @@
|
|||
public void Dispose()
|
||||
{
|
||||
Navigation.LocationChanged -= OnLocationChanged;
|
||||
_autosaveTimer?.Dispose();
|
||||
}
|
||||
|
||||
private void OnContentChanged(ChangeEventArgs e)
|
||||
{
|
||||
editorContent = e.Value?.ToString() ?? string.Empty;
|
||||
_contentModified = editorContent != _lastSavedContent;
|
||||
ResetAutosaveTimer();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void ResetAutosaveTimer()
|
||||
{
|
||||
_autosaveTimer?.Dispose();
|
||||
_autosaveTimer = new Timer(AutosaveCallback, null, TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
|
||||
}
|
||||
|
||||
private async void AutosaveCallback(object? state)
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentFile) || !_contentModified || isChecking) return;
|
||||
|
||||
try
|
||||
{
|
||||
await InvokeAsync(async () =>
|
||||
{
|
||||
await File.WriteAllTextAsync(currentFile, editorContent);
|
||||
_lastSavedContent = editorContent;
|
||||
_contentModified = false;
|
||||
statusText = Loc["editor.status.autosaved"];
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenAssistant()
|
||||
|
|
@ -248,32 +349,42 @@
|
|||
{
|
||||
currentFile = filePath;
|
||||
editorContent = await File.ReadAllTextAsync(filePath);
|
||||
statusText = $"{T("Geladen:", "Loaded:")} {Path.GetFileName(filePath)}";
|
||||
_lastSavedContent = editorContent;
|
||||
_contentModified = false;
|
||||
statusText = $"{Loc["editor.status.loaded"]} {Path.GetFileName(filePath)}";
|
||||
RefreshLatestVersion();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearResults()
|
||||
{
|
||||
showSpellDiff = false;
|
||||
showVersionBrowser = false;
|
||||
showVersionDiff = false;
|
||||
ragResults = null;
|
||||
wikipediaResults = null;
|
||||
analysisResult = string.Empty;
|
||||
}
|
||||
|
||||
private async Task CheckStyle()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(editorContent)) return;
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Ollama analysiert Stil...", "Ollama analyzing style...");
|
||||
statusText = Loc["editor.status.analyzing_style"];
|
||||
checkProgress = 50;
|
||||
showSpellDiff = false;
|
||||
ragResults = null;
|
||||
wikipediaResults = null;
|
||||
ClearResults();
|
||||
|
||||
try
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
isChecking = false;
|
||||
checkProgress = 0;
|
||||
}
|
||||
|
|
@ -284,11 +395,9 @@
|
|||
if (string.IsNullOrWhiteSpace(editorContent)) return;
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Ollama pr\u00fcft Rechtschreibung...", "Ollama checking spelling...");
|
||||
statusText = Loc["editor.status.checking_spelling"];
|
||||
checkProgress = 50;
|
||||
showSpellDiff = false;
|
||||
ragResults = null;
|
||||
wikipediaResults = null;
|
||||
ClearResults();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -298,32 +407,40 @@
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
isChecking = false;
|
||||
checkProgress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySpellCorrections()
|
||||
{
|
||||
if (string.IsNullOrEmpty(correctedText)) return;
|
||||
editorContent = correctedText;
|
||||
_contentModified = editorContent != _lastSavedContent;
|
||||
showSpellDiff = false;
|
||||
ResetAutosaveTimer();
|
||||
statusText = Loc["editor.status.corrections_applied"];
|
||||
}
|
||||
|
||||
private async Task RagSearch()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Suche verwandte Fakten...", "Searching related facts...");
|
||||
showSpellDiff = false;
|
||||
statusText = Loc["editor.status.searching_rag"];
|
||||
ClearResults();
|
||||
analysisResult = string.Empty;
|
||||
ragResults = null;
|
||||
wikipediaResults = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (currentProjectId == 0)
|
||||
{
|
||||
analysisResult = T("Kein Projekt geladen. \u00d6ffne zuerst ein Projekt \u00fcber die Sidebar.", "No project loaded. Open a project via the sidebar first.");
|
||||
analysisResult = Loc["editor.rag.error.no_project"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -331,16 +448,16 @@
|
|||
|
||||
if (ragResults.Count == 0)
|
||||
{
|
||||
analysisResult = T("Keine relevanten Fakten gefunden. Indexiere das Projekt ggf. \u00fcber 'Projekt indexieren'.", "No relevant facts found. Index the project if needed via 'Index project'.");
|
||||
analysisResult = Loc["editor.rag.error.no_facts"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("RAG-Fehler:", "RAG error:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["editor.rag.error.generic"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
isChecking = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -350,11 +467,9 @@
|
|||
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Suche auf Wikipedia...", "Searching Wikipedia...");
|
||||
showSpellDiff = false;
|
||||
statusText = Loc["editor.status.searching_wikipedia"];
|
||||
ClearResults();
|
||||
analysisResult = string.Empty;
|
||||
ragResults = null;
|
||||
wikipediaResults = null;
|
||||
loadedArticles.Clear();
|
||||
|
||||
try
|
||||
|
|
@ -377,22 +492,22 @@
|
|||
}
|
||||
|
||||
if (wikipediaResults.Count == 0)
|
||||
analysisResult = T("Keine Wikipedia-Artikel gefunden.", "No Wikipedia articles found.");
|
||||
analysisResult = Loc["editor.wikipedia.error.not_found"];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("Wikipedia-Fehler:", "Wikipedia error:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["editor.wikipedia.error.generic"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
isChecking = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadFullArticle(WikipediaResult result)
|
||||
{
|
||||
statusText = $"{T("Lade Artikel:", "Loading article:")} {result.Title}...";
|
||||
statusText = $"{Loc["editor.status.loading_article"]} {result.Title}...";
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -401,16 +516,16 @@
|
|||
{
|
||||
result.Extract = fullText;
|
||||
loadedArticles[result.Url] = true;
|
||||
statusText = T("Artikel geladen.", "Article loaded.");
|
||||
statusText = Loc["editor.wikipedia.status.loaded"];
|
||||
}
|
||||
else
|
||||
{
|
||||
statusText = T("Konnte Artikel nicht laden.", "Could not load article.");
|
||||
statusText = Loc["editor.wikipedia.error.load_failed"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +533,7 @@
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(result.Extract) || currentProjectId == 0) return;
|
||||
|
||||
statusText = T("Speichere als Fakt...", "Saving as fact...");
|
||||
statusText = Loc["editor.status.saving_fact"];
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -426,7 +541,7 @@
|
|||
var project = projects.FirstOrDefault(p => p.Id == currentProjectId);
|
||||
if (project == null)
|
||||
{
|
||||
statusText = T("Projekt nicht gefunden.", "Project not found.");
|
||||
statusText = Loc["editor.error.project_not_found"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -443,11 +558,11 @@
|
|||
result.Extract;
|
||||
|
||||
await File.WriteAllTextAsync(filePath, content);
|
||||
statusText = $"{T("Gespeichert als:", "Saved as:")} {safeName}.md";
|
||||
statusText = $"{Loc["editor.status.saved_as"]} {safeName}.md";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{T("Fehler beim Speichern:", "Error saving:")} {ex.Message}";
|
||||
statusText = $"{Loc["editor.error.save_failed"]} {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,7 +584,7 @@
|
|||
if (string.IsNullOrWhiteSpace(newProjectName) || string.IsNullOrWhiteSpace(newProjectPath)) return;
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Erstelle Projekt...", "Creating project...");
|
||||
statusText = Loc["editor.status.creating_project"];
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -482,12 +597,12 @@
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("Fehler beim Erstellen:", "Error creating:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["editor.error.create_failed"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
isChecking = false;
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -495,12 +610,12 @@
|
|||
{
|
||||
if (currentProjectId == 0)
|
||||
{
|
||||
analysisResult = T("Kein Projekt geladen. \u00d6ffne zuerst ein Projekt \u00fcber die Sidebar.", "No project loaded. Open a project via the sidebar first.");
|
||||
analysisResult = Loc["editor.index.error.no_project"];
|
||||
return;
|
||||
}
|
||||
|
||||
isChecking = true;
|
||||
statusText = T("Indexiere Projekt...", "Indexing project...");
|
||||
statusText = Loc["editor.status.indexing"];
|
||||
analysisResult = string.Empty;
|
||||
ragResults = null;
|
||||
|
||||
|
|
@ -510,7 +625,7 @@
|
|||
var project = projects.FirstOrDefault(p => p.Id == currentProjectId);
|
||||
if (project == null)
|
||||
{
|
||||
analysisResult = T("Projekt nicht gefunden.", "Project not found.");
|
||||
analysisResult = Loc["editor.index.error.not_found"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -521,15 +636,15 @@
|
|||
});
|
||||
|
||||
await RagService.IndexProjectAsync(currentProjectId, project.RootPath, p);
|
||||
analysisResult = T("Projekt erfolgreich indexiert.", "Project indexed successfully.");
|
||||
analysisResult = Loc["editor.index.status.success"];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
analysisResult = $"{T("Indexierungsfehler:", "Indexing error:")} {ex.Message}";
|
||||
analysisResult = $"{Loc["editor.index.error.generic"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
isChecking = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -538,7 +653,9 @@
|
|||
{
|
||||
if (string.IsNullOrEmpty(currentFile)) return;
|
||||
await File.WriteAllTextAsync(currentFile, editorContent);
|
||||
statusText = $"{T("Gespeichert:", "Saved:")} {Path.GetFileName(currentFile)}";
|
||||
_lastSavedContent = editorContent;
|
||||
_contentModified = false;
|
||||
statusText = $"{Loc["editor.status.saved"]} {Path.GetFileName(currentFile)}";
|
||||
}
|
||||
|
||||
private void ShowVersionDialog()
|
||||
|
|
@ -565,12 +682,98 @@
|
|||
var meta = $"Kommentar: {versionComment}";
|
||||
await File.WriteAllTextAsync(versionPath + ".meta", meta);
|
||||
|
||||
statusText = $"{T("Version gespeichert:", "Version saved:")} {name}_{stamp}{ext}";
|
||||
statusText = $"{Loc["editor.status.version_saved"]} {name}_{stamp}{ext}";
|
||||
showVersionDialog = false;
|
||||
versionComment = string.Empty;
|
||||
_lastSavedContent = editorContent;
|
||||
_contentModified = false;
|
||||
RefreshLatestVersion();
|
||||
}
|
||||
|
||||
private void ShowVersionBrowser()
|
||||
{
|
||||
ClearResults();
|
||||
LoadVersionList();
|
||||
showVersionBrowser = true;
|
||||
}
|
||||
|
||||
private void CloseVersionBrowser()
|
||||
{
|
||||
showVersionBrowser = false;
|
||||
showVersionDiff = false;
|
||||
_selectedVersion = null;
|
||||
}
|
||||
|
||||
private void LoadVersionList()
|
||||
{
|
||||
_versionList.Clear();
|
||||
if (string.IsNullOrEmpty(currentFile)) return;
|
||||
|
||||
var dir = Path.GetDirectoryName(currentFile)!;
|
||||
var name = Path.GetFileNameWithoutExtension(currentFile);
|
||||
var ext = Path.GetExtension(currentFile);
|
||||
var versionsDir = Path.Combine(dir, "_versions");
|
||||
if (!Directory.Exists(versionsDir)) return;
|
||||
|
||||
var pattern = $"{name}_*{ext}";
|
||||
var files = Directory.GetFiles(versionsDir, pattern).OrderByDescending(f => f).ToList();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var metaFile = file + ".meta";
|
||||
string? comment = null;
|
||||
if (File.Exists(metaFile))
|
||||
{
|
||||
var lines = File.ReadAllLines(metaFile);
|
||||
if (lines.Length > 0 && lines[0].StartsWith("Kommentar: "))
|
||||
comment = lines[0]["Kommentar: ".Length..];
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileNameWithoutExtension(file);
|
||||
var stamp = fileName[(name.Length + 1)..];
|
||||
var parsed = DateTime.TryParseExact(stamp, "yyyyMMdd_HHmmss", null,
|
||||
System.Globalization.DateTimeStyles.None, out var dt);
|
||||
|
||||
_versionList.Add(new VersionEntry(
|
||||
file,
|
||||
parsed ? dt : File.GetLastWriteTime(file),
|
||||
comment
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private async void ShowVersionDiff(VersionEntry version)
|
||||
{
|
||||
try
|
||||
{
|
||||
_versionDiffContent = await File.ReadAllTextAsync(version.FilePath);
|
||||
_selectedVersion = version;
|
||||
showVersionDiff = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private async void RestoreVersion(VersionEntry version)
|
||||
{
|
||||
try
|
||||
{
|
||||
editorContent = await File.ReadAllTextAsync(version.FilePath);
|
||||
_contentModified = editorContent != _lastSavedContent;
|
||||
ResetAutosaveTimer();
|
||||
statusText = $"{Loc["editor.version.status_loaded_prefix"]} {version.Timestamp:dd.MM.yyyy HH:mm} {Loc["editor.version.status_loaded_suffix"]}";
|
||||
showVersionBrowser = false;
|
||||
showVersionDiff = false;
|
||||
_selectedVersion = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshLatestVersion()
|
||||
{
|
||||
latestVersion = null;
|
||||
|
|
@ -606,18 +809,4 @@
|
|||
comment
|
||||
);
|
||||
}
|
||||
|
||||
private async Task LoadLatestVersion()
|
||||
{
|
||||
if (latestVersion == null) return;
|
||||
try
|
||||
{
|
||||
editorContent = await File.ReadAllTextAsync(latestVersion.FilePath);
|
||||
statusText = $"{T("Version vom", "Version from")} {latestVersion.Timestamp:dd.MM.yyyy HH:mm} {T("geladen.", "loaded.")}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusText = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
@page "/Error"
|
||||
@inject ISettingsService SettingsService
|
||||
@inject ILocalizationService Loc
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>@T("Fehler", "Error")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.error"]</PageTitle>
|
||||
|
||||
<h1>@T("Ein Fehler ist aufgetreten", "An error occurred")</h1>
|
||||
<p>@T("Entschuldigung, es ist ein unerwarteter Fehler aufgetreten.", "Sorry, an unexpected error occurred.")</p>
|
||||
<a href="/">@T("Zurück zur Startseite", "Back to home")</a>
|
||||
<h1>@Loc["error.heading"]</h1>
|
||||
<p>@Loc["error.message"]</p>
|
||||
<a href="/">@Loc["error.link.back_to_home"]</a>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
|
||||
if (HttpContext is not null)
|
||||
{
|
||||
HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
@attribute [Authorize]
|
||||
@inject IOllamaService OllamaService
|
||||
@inject IProjectService ProjectService
|
||||
@inject ISettingsService SettingsService
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
<PageTitle>@T("Dashboard - Author Buddy", "Dashboard - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.home"]</PageTitle>
|
||||
|
||||
<div class="tab-bar">
|
||||
<div class="tab @GetTabClass("rag")" @onclick='() => activeTab = "rag"'>@T("Gefundene Fakten (RAG)", "Found facts (RAG)")</div>
|
||||
<div class="tab @GetTabClass("style")" @onclick='() => activeTab = "style"'>@T("Stil-Analyse", "Style analysis")</div>
|
||||
<div class="tab @GetTabClass("rag")" @onclick='() => activeTab = "rag"'>@Loc["home.tab.rag_facts"]</div>
|
||||
<div class="tab @GetTabClass("style")" @onclick='() => activeTab = "style"'>@Loc["home.tab.style_analysis"]</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
{
|
||||
@if (foundFacts.Count == 0)
|
||||
{
|
||||
<p style="color: var(--border-color);">@T("Keine Fakten gefunden. Öffne ein Projekt und scanne die Dateien.", "No facts found. Open a project and scan the files.")</p>
|
||||
<p style="color: var(--border-color);">@Loc["home.rag.empty"]</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -33,18 +33,10 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string activeTab = "rag";
|
||||
private List<string> foundFacts = new();
|
||||
private string styleSuggestions = string.Empty;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
}
|
||||
|
||||
private string GetTabClass(string tab)
|
||||
{
|
||||
return activeTab == tab ? "active" : "";
|
||||
|
|
|
|||
|
|
@ -3,39 +3,43 @@
|
|||
@inject CustomAuthStateProvider AuthStateProvider
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISettingsService SettingsService
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>@T("Anmelden - Author Buddy", "Login - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.login"]</PageTitle>
|
||||
|
||||
<div class="auth-page">
|
||||
<div class="auth-card">
|
||||
<h2>@T("Anmelden", "Login")</h2>
|
||||
<div class="auth-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<h2>@Loc["login.heading"]</h2>
|
||||
|
||||
@if (!show2FA)
|
||||
{
|
||||
<div class="form-group">
|
||||
<label for="username">@T("Benutzername:", "Username:")</label>
|
||||
<label for="username">@Loc["login.label.username"]</label>
|
||||
<input id="username" @bind="username" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">@T("Passwort:", "Password:")</label>
|
||||
<label for="password">@Loc["login.label.password"]</label>
|
||||
<input id="password" type="password" @bind="password" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="auth-actions">
|
||||
<button @onclick="DoLogin" disabled="@isBusy">@T("Anmelden", "Login")</button>
|
||||
<a href="/register">@T("Registrieren", "Register")</a>
|
||||
<button @onclick="DoLogin" disabled="@isBusy">@Loc["login.button.submit"]</button>
|
||||
<a href="/register">@Loc["login.link.register"]</a>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>@T("Gib den 6-stelligen Code aus deiner Authenticator-App ein:", "Enter the 6-digit code from your authenticator app:")</p>
|
||||
<p>@Loc["login.2fa.instruction"]</p>
|
||||
<div class="form-group">
|
||||
<label for="code">@T("2FA-Code:", "2FA code:")</label>
|
||||
<label for="code">@Loc["login.2fa.label.code"]</label>
|
||||
<input id="code" @bind="twoFactorCode" maxlength="6" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="auth-actions">
|
||||
<button @onclick="Verify2FA" disabled="@isBusy">@T("Bestätigen", "Verify")</button>
|
||||
<button @onclick="Verify2FA" disabled="@isBusy">@Loc["login.2fa.button.verify"]</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +51,6 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string username = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string twoFactorCode = string.Empty;
|
||||
|
|
@ -55,12 +58,8 @@
|
|||
private bool isBusy;
|
||||
private bool show2FA;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
|
||||
if (AuthService.IsLoggedIn)
|
||||
{
|
||||
Navigation.NavigateTo("/");
|
||||
|
|
@ -95,7 +94,7 @@
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
errorMessage = T("Bitte Benutzername und Passwort eingeben.", "Please enter username and password.");
|
||||
errorMessage = Loc["login.error.empty_fields"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -117,12 +116,12 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
errorMessage = T("Benutzername oder Passwort falsch.", "Invalid username or password.");
|
||||
errorMessage = Loc["login.error.invalid_credentials"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -134,7 +133,7 @@
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(twoFactorCode) || twoFactorCode.Length != 6)
|
||||
{
|
||||
errorMessage = T("Bitte gib einen gültigen 6-stelligen Code ein.", "Please enter a valid 6-digit code.");
|
||||
errorMessage = Loc["login.2fa.error.invalid_code"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -151,12 +150,12 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
errorMessage = T("Ungültiger Code. Bitte versuche es erneut.", "Invalid code. Please try again.");
|
||||
errorMessage = Loc["login.2fa.error.code_failed"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
@page "/models"
|
||||
@attribute [Authorize]
|
||||
@inject IOllamaService OllamaService
|
||||
@inject ISettingsService SettingsService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
|
||||
<PageTitle>@T("Modelle - Author Buddy", "Models - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.models"]</PageTitle>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||||
<h3>@T("Ollama Modelle verwalten", "Manage Ollama models")</h3>
|
||||
<button @onclick="RefreshModels" disabled="@isLoading">@T("Aktualisieren", "Refresh")</button>
|
||||
<h3>@Loc["models.heading"]</h3>
|
||||
<button @onclick="RefreshModels" disabled="@isLoading">@Loc["models.button.refresh"]</button>
|
||||
</div>
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p>@T("Lade Modelle...", "Loading models...")</p>
|
||||
<p>@Loc["models.status.loading"]</p>
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
|
|
@ -28,8 +28,8 @@ else
|
|||
<div class="model-card">
|
||||
<div class="model-name">@model.Name</div>
|
||||
<div class="model-details">
|
||||
@T("Größe:", "Size:") @FormatSize(model.Size) |
|
||||
@T("Geändert:", "Modified:") @model.ModifiedAt?.ToString("g")
|
||||
@Loc["models.label.size"] @FormatSize(model.Size) |
|
||||
@Loc["models.label.modified"] @model.ModifiedAt?.ToString("g")
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -37,14 +37,14 @@ else
|
|||
}
|
||||
|
||||
<div style="margin-top: 24px; border-top: 1px solid var(--border-color); padding-top: 16px;">
|
||||
<h4 style="margin-bottom: 8px;">@T("Neues Modell herunterladen", "Download new model")</h4>
|
||||
<h4 style="margin-bottom: 8px;">@Loc["models.pull.heading"]</h4>
|
||||
<div style="display: flex; gap: 8px; align-items: flex-end;">
|
||||
<div class="form-group" style="flex: 1; margin-bottom: 0;">
|
||||
<label for="pullModelName">@T("Modellname:", "Model name:")</label>
|
||||
<input id="pullModelName" @bind="modelToPull" placeholder="@T("z.B. llama3.2", "e.g. llama3.2")" />
|
||||
<label for="pullModelName">@Loc["models.pull.label.name"]</label>
|
||||
<input id="pullModelName" @bind="modelToPull" placeholder="@Loc["models.pull.placeholder"]" />
|
||||
</div>
|
||||
<button @onclick="PullModel" disabled="@(isPulling || string.IsNullOrWhiteSpace(modelToPull))">
|
||||
@T("Herunterladen", "Download")
|
||||
@Loc["models.pull.button.download"]
|
||||
</button>
|
||||
</div>
|
||||
@if (isPulling)
|
||||
|
|
@ -66,7 +66,6 @@ else
|
|||
}
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private List<LLM_Model> localModels = new();
|
||||
private bool isLoading;
|
||||
private string? errorMessage;
|
||||
|
|
@ -77,11 +76,8 @@ else
|
|||
private string? pullResult;
|
||||
private string pullPercentDisplay => $"{pullProgress:F0}%";
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
await RefreshModels();
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +93,7 @@ else
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler beim Laden der Modelle:", "Error loading models:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["models.error.loading"]} {ex.Message}";
|
||||
localModels = new();
|
||||
}
|
||||
finally
|
||||
|
|
@ -112,7 +108,7 @@ else
|
|||
|
||||
isPulling = true;
|
||||
pullProgress = 0;
|
||||
pullStatus = T("Starte Download...", "Starting download...");
|
||||
pullStatus = Loc["models.pull.status.starting"];
|
||||
pullResult = null;
|
||||
|
||||
try
|
||||
|
|
@ -124,13 +120,13 @@ else
|
|||
});
|
||||
|
||||
await OllamaService.PullModelAsync(modelToPull, progress);
|
||||
pullResult = $"{T("Modell", "Model")} '{modelToPull}' {T("erfolgreich heruntergeladen.", "downloaded successfully.")}";
|
||||
pullResult = $"{Loc["models.pull.status.model"]} '{modelToPull}' {Loc["models.pull.status.success"]}";
|
||||
modelToPull = string.Empty;
|
||||
await RefreshModels();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
pullResult = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
pullResult = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
@page "/not-found"
|
||||
@inject ISettingsService SettingsService
|
||||
@inject ILocalizationService Loc
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>@T("Seite nicht gefunden", "Page not found")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.not_found"]</PageTitle>
|
||||
|
||||
<h1>@T("404 - Seite nicht gefunden", "404 - Page not found")</h1>
|
||||
<p>@T("Die angeforderte Seite existiert nicht.", "The requested page does not exist.")</p>
|
||||
<a href="/">@T("Zurück zur Startseite", "Back to home")</a>
|
||||
<h1>@Loc["notfound.heading"]</h1>
|
||||
<p>@Loc["notfound.message"]</p>
|
||||
<a href="/">@Loc["notfound.link.back_to_home"]</a>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
|
||||
if (HttpContext is not null)
|
||||
{
|
||||
HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
|
||||
|
|
|
|||
|
|
@ -3,23 +3,24 @@
|
|||
@inject IOllamaService OllamaService
|
||||
@inject ISettingsService SettingsService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>@T("Assistent - Author Buddy", "Assistant - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.assistant"]</PageTitle>
|
||||
|
||||
<div class="assistant-page">
|
||||
<div class="assistant-toolbar">
|
||||
<select @bind="selectedMode">
|
||||
<option value="lektorat">@T("Lektorat", "Editing")</option>
|
||||
<option value="advocatus">@T("Advocatus Diaboli", "Advocatus Diaboli")</option>
|
||||
<option value="hookfinder">@T("Hook-Finder", "Hook finder")</option>
|
||||
<option value="eli5">@T("ELI5-Vereinfachung", "ELI5 simplification")</option>
|
||||
<option value="lektorat">@Loc["assistant.mode.lektorat"]</option>
|
||||
<option value="advocatus">@Loc["assistant.mode.advocatus"]</option>
|
||||
<option value="hookfinder">@Loc["assistant.mode.hookfinder"]</option>
|
||||
<option value="eli5">@Loc["assistant.mode.eli5"]</option>
|
||||
</select>
|
||||
<button @onclick="RunAssistant" disabled="@(() => isRunning || string.IsNullOrWhiteSpace(inputText))">@T("Ausführen", "Execute")</button>
|
||||
<button @onclick="RunAssistant" disabled="@(() => isRunning || string.IsNullOrWhiteSpace(inputText))">@Loc["assistant.button.execute"]</button>
|
||||
@if (!string.IsNullOrEmpty(outputText))
|
||||
{
|
||||
<button @onclick="SendToEditor" class="primary">@T("An Editor übermitteln", "Send to editor")</button>
|
||||
<button @onclick="SendToEditor" class="primary">@Loc["assistant.button.send_to_editor"]</button>
|
||||
}
|
||||
<span style="flex:1;font-size:12px;color:var(--border-color);text-align:right;">@statusText</span>
|
||||
@if (isRunning)
|
||||
|
|
@ -30,11 +31,11 @@
|
|||
|
||||
<div class="assistant-panels">
|
||||
<div class="assistant-input-panel">
|
||||
<h4>@T("Eingabetext", "Input text")</h4>
|
||||
<textarea class="assistant-textarea" @bind="inputText" placeholder="@T("Füge hier deinen Text ein...", "Paste your text here...")"></textarea>
|
||||
<h4>@Loc["assistant.label.input_text"]</h4>
|
||||
<textarea class="assistant-textarea" @bind="inputText" placeholder="@Loc["assistant.placeholder.input"]"></textarea>
|
||||
</div>
|
||||
<div class="assistant-output-panel">
|
||||
<h4>@T("Ergebnis", "Result")</h4>
|
||||
<h4>@Loc["assistant.label.result"]</h4>
|
||||
<div class="assistant-output">
|
||||
@if (!string.IsNullOrEmpty(outputText))
|
||||
{
|
||||
|
|
@ -46,7 +47,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
<span class="assistant-hint">@T("Ergebnis erscheint hier nach der Ausführung.", "Result appears here after execution.")</span>
|
||||
<span class="assistant-hint">@Loc["assistant.hint.empty_result"]</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -54,7 +55,6 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string selectedMode = "lektorat";
|
||||
private string inputText = string.Empty;
|
||||
private string outputText = string.Empty;
|
||||
|
|
@ -63,12 +63,9 @@
|
|||
private bool isRunning;
|
||||
private double progress;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
statusText = T("Bereit", "Ready");
|
||||
statusText = Loc["common.status.ready"];
|
||||
|
||||
var pending = SettingsService.PendingAssistantInput;
|
||||
if (!string.IsNullOrEmpty(pending))
|
||||
|
|
@ -86,7 +83,7 @@
|
|||
progress = 50;
|
||||
outputText = string.Empty;
|
||||
errorMessage = string.Empty;
|
||||
statusText = T("Verarbeite...", "Processing...");
|
||||
statusText = Loc["assistant.status.processing"];
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -101,18 +98,18 @@
|
|||
|
||||
if (string.IsNullOrEmpty(systemPrompt))
|
||||
{
|
||||
errorMessage = T("Kein System-Prompt für diesen Modus konfiguriert. Bitte in den Einstellungen hinterlegen.", "No system prompt configured for this mode. Please configure in settings.");
|
||||
errorMessage = Loc["assistant.error.no_prompt"];
|
||||
return;
|
||||
}
|
||||
|
||||
var model = await SettingsService.GetStyleModelAsync() ?? "llama3.2";
|
||||
outputText = await OllamaService.Chat(model, inputText, systemPrompt);
|
||||
statusText = T("Fertig.", "Done.");
|
||||
statusText = Loc["assistant.status.done"];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
statusText = T("Fehler", "Error");
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
statusText = Loc["common.status.error"];
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,31 +2,34 @@
|
|||
@inject IAuthService AuthService
|
||||
@inject CustomAuthStateProvider AuthStateProvider
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISettingsService SettingsService
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>@T("Registrieren - Author Buddy", "Register - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.register"]</PageTitle>
|
||||
|
||||
<div class="auth-page">
|
||||
<div class="auth-card">
|
||||
<h2>@T("Registrieren", "Register")</h2>
|
||||
<div class="auth-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<h2>@Loc["register.heading"]</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">@T("Benutzername:", "Username:")</label>
|
||||
<label for="username">@Loc["register.label.username"]</label>
|
||||
<input id="username" @bind="username" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">@T("Passwort:", "Password:")</label>
|
||||
<label for="password">@Loc["register.label.password"]</label>
|
||||
<input id="password" type="password" @bind="password" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword">@T("Passwort bestätigen:", "Confirm password:")</label>
|
||||
<label for="confirmPassword">@Loc["register.label.confirm_password"]</label>
|
||||
<input id="confirmPassword" type="password" @bind="confirmPassword" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
<div class="auth-actions">
|
||||
<button @onclick="DoRegister" disabled="@isBusy">@T("Registrieren", "Register")</button>
|
||||
<a href="/login">@T("Zurück zum Login", "Back to login")</a>
|
||||
<button @onclick="DoRegister" disabled="@isBusy">@Loc["register.button.submit"]</button>
|
||||
<a href="/login">@Loc["register.link.back_to_login"]</a>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(errorMessage))
|
||||
|
|
@ -37,20 +40,12 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string username = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string confirmPassword = string.Empty;
|
||||
private string errorMessage = string.Empty;
|
||||
private bool isBusy;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
}
|
||||
|
||||
private async Task HandleKeyDown(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
|
|
@ -61,22 +56,22 @@
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
errorMessage = T("Bitte Benutzername eingeben.", "Please enter a username.");
|
||||
errorMessage = Loc["register.error.no_username"];
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
errorMessage = T("Bitte Passwort eingeben.", "Please enter a password.");
|
||||
errorMessage = Loc["register.error.no_password"];
|
||||
return;
|
||||
}
|
||||
if (password != confirmPassword)
|
||||
{
|
||||
errorMessage = T("Passwörter stimmen nicht überein.", "Passwords do not match.");
|
||||
errorMessage = Loc["register.error.password_mismatch"];
|
||||
return;
|
||||
}
|
||||
if (password.Length < 4)
|
||||
{
|
||||
errorMessage = T("Passwort muss mindestens 4 Zeichen lang sein.", "Password must be at least 4 characters long.");
|
||||
errorMessage = Loc["register.error.password_too_short"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -93,12 +88,12 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
errorMessage = T("Benutzername ist bereits vergeben.", "Username is already taken.");
|
||||
errorMessage = Loc["register.error.username_taken"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,46 +6,58 @@
|
|||
@inject NavigationManager Navigation
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject IProjectService ProjectService
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
<PageTitle>@T("Einstellungen", "Settings") - Author Buddy</PageTitle>
|
||||
<PageTitle>@Loc["page.title.settings"] - Author Buddy</PageTitle>
|
||||
|
||||
<div class="settings-page">
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Benutzer", "User")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.user"]</h3>
|
||||
<div class="form-group">
|
||||
<label for="userSelect">@T("Aktiver Benutzer:", "Active user:")</label>
|
||||
<label for="userSelect">@Loc["settings.user.label.active"]</label>
|
||||
<select id="userSelect" value="@selectedUserId" @onchange="SwitchUser">
|
||||
@foreach (var u in users)
|
||||
{
|
||||
<option value="@u.Id">@u.Name</option>
|
||||
<option value="@u.Id">@u.Name (@(u.Role == AuthorBuddy.Web.Data.UserRole.Administrator ? Loc["settings.user.role.admin"] : Loc["settings.user.role.author"]))</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="newUserName">@T("Neuer Benutzer:", "New user:")</label>
|
||||
<label for="newUserName">@Loc["settings.user.label.new"]</label>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<input id="newUserName" @bind="newUserName" placeholder="@T("Name", "Name")" style="flex: 1;" />
|
||||
<button class="btn btn-secondary" @onclick="AddUser">@T("Hinzuf\u00fcgen", "Add")</button>
|
||||
<input id="newUserName" @bind="newUserName" placeholder="@Loc["settings.user.placeholder.name"]" style="flex: 1;" />
|
||||
<button class="btn btn-secondary" @onclick="AddUser">@Loc["settings.user.button.add"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section" style="margin-bottom:16px;">
|
||||
<button class="btn btn-secondary" @onclick='() => Navigation.NavigateTo("/setup-2fa")'>@T("2FA einrichten", "Set up 2FA")</button>
|
||||
<button class="btn btn-secondary" @onclick='() => Navigation.NavigateTo("/setup-2fa")'>@Loc["settings.user.link.2fa"]</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-context">
|
||||
@if (currentProjectName != null)
|
||||
{
|
||||
<span class="settings-badge settings-badge-project">@Loc["settings.context.project"]: @currentProjectName</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="settings-badge settings-badge-user">@Loc["settings.context.user"]</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="settings-layout">
|
||||
|
||||
<div class="settings-column" >
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Modelle", "Models")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.models"]</h3>
|
||||
<div class="form-group">
|
||||
<label for="ragModel">@T("RAG-Modell (Faktenabfrage):", "RAG model (facts):")</label>
|
||||
<label for="ragModel">@Loc["settings.models.label.rag"]</label>
|
||||
<select id="ragModel" @bind="ragModel">
|
||||
@if (availableModels.Count == 0)
|
||||
{
|
||||
<option value="">@T("Keine Modelle gefunden", "No models found")</option>
|
||||
<option value="">@Loc["settings.models.empty"]</option>
|
||||
}
|
||||
@foreach (var m in availableModels)
|
||||
{
|
||||
|
|
@ -54,11 +66,11 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="styleModel">@T("Stil-Modell (Lektorat):", "Style model (editing):")</label>
|
||||
<label for="styleModel">@Loc["settings.models.label.style"]</label>
|
||||
<select id="styleModel" @bind="styleModel">
|
||||
@if (availableModels.Count == 0)
|
||||
{
|
||||
<option value="">@T("Keine Modelle gefunden", "No models found")</option>
|
||||
<option value="">@Loc["settings.models.empty"]</option>
|
||||
}
|
||||
@foreach (var m in availableModels)
|
||||
{
|
||||
|
|
@ -67,11 +79,11 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spellingModel">@T("Rechtschreibpr\u00fcfungs-Modell:", "Spell check model:")</label>
|
||||
<label for="spellingModel">@Loc["settings.models.label.spellcheck"]</label>
|
||||
<select id="spellingModel" @bind="spellingModel">
|
||||
@if (availableModels.Count == 0)
|
||||
{
|
||||
<option value="">@T("Keine Modelle gefunden", "No models found")</option>
|
||||
<option value="">@Loc["settings.models.empty"]</option>
|
||||
}
|
||||
@foreach (var m in availableModels)
|
||||
{
|
||||
|
|
@ -82,30 +94,30 @@
|
|||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Ollama Server", "Ollama Server")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.ollama_server"]</h3>
|
||||
<div class="form-group">
|
||||
<label for="ollamaUrl">@T("Server-URL:", "Server URL:")</label>
|
||||
<label for="ollamaUrl">@Loc["settings.ollama.label.url"]</label>
|
||||
<input id="ollamaUrl" @bind="ollamaUrl" placeholder="http://localhost:11434" />
|
||||
<div class="form-hint">@T("Adresse des Ollama-Servers", "Ollama server address")</div>
|
||||
<div class="form-hint">@Loc["settings.ollama.hint.url"]</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Design", "Appearance")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.appearance"]</h3>
|
||||
<div class="form-group">
|
||||
<label for="themeSelect">@T("Theme:", "Theme:")</label>
|
||||
<label for="themeSelect">@Loc["settings.appearance.label.theme"]</label>
|
||||
<select id="themeSelect" @bind="selectedTheme">
|
||||
<option value="light">@T("Hell", "Light")</option>
|
||||
<option value="dark">@T("Dunkel", "Dark")</option>
|
||||
<option value="w95">W95 @T("(Retro)", "(Retro)")</option>
|
||||
<option value="light">@Loc["settings.appearance.theme.light"]</option>
|
||||
<option value="dark">@Loc["settings.appearance.theme.dark"]</option>
|
||||
<option value="w95">W95 @Loc["settings.appearance.theme.retro"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Sprache", "Language")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.language"]</h3>
|
||||
<div class="form-group">
|
||||
<label for="languageSelect">@T("Sprache:", "Language:")</label>
|
||||
<label for="languageSelect">@Loc["settings.language.label"]</label>
|
||||
<select id="languageSelect" @bind="selectedLanguage">
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="en">English</option>
|
||||
|
|
@ -116,21 +128,21 @@
|
|||
|
||||
<div class="settings-column" >
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Lektor-System-Prompt", "Editor system prompt")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.editor_prompt"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="lektorPrompt" @bind="lektorPrompt" rows="6"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Fact-Check-Vorlage", "Fact check template")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.factcheck_template"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="factCheckTemplate" @bind="factCheckTemplate" rows="6"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Rechtschreibpr\u00fcfungs-Prompt", "Spell check prompt")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.spellcheck_prompt"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="spellingPrompt" @bind="spellingPrompt" rows="6"></textarea>
|
||||
</div>
|
||||
|
|
@ -139,21 +151,21 @@
|
|||
|
||||
<div class="settings-column" >
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Advocatus Diaboli", "Advocatus Diaboli")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.advocatus_diaboli"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="advocatusDiaboliPrompt" @bind="advocatusDiaboliPrompt" rows="6"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("Hook-Finder", "Hook finder")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.hook_finder"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="hookFinderPrompt" @bind="hookFinderPrompt" rows="6"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">@T("ELI5-Vereinfachung", "ELI5-Simplification")</h3>
|
||||
<h3 class="settings-section-title">@Loc["settings.section.eli5"]</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="eli5Prompt" @bind="eli5Prompt" rows="6"></textarea>
|
||||
</div>
|
||||
|
|
@ -163,7 +175,7 @@
|
|||
</div>
|
||||
|
||||
<div class="settings-actions">
|
||||
<button class="btn btn-primary" @onclick="SaveSettings">@T("Speichern", "Save")</button>
|
||||
<button class="btn btn-primary" @onclick="SaveSettings">@Loc["settings.button.save"]</button>
|
||||
@if (!string.IsNullOrEmpty(statusMessage))
|
||||
{
|
||||
<span class="settings-status">@statusMessage</span>
|
||||
|
|
@ -191,8 +203,7 @@
|
|||
private List<LLM_Model> availableModels = new();
|
||||
private List<UserEntity> users = new();
|
||||
private int selectedUserId;
|
||||
|
||||
private string T(string de, string en) => selectedLanguage == "en" ? en : de;
|
||||
private string? currentProjectName;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
|
@ -200,6 +211,13 @@
|
|||
var current = await SettingsService.GetCurrentUserAsync();
|
||||
selectedUserId = current.Id;
|
||||
|
||||
var pid = SettingsService.CurrentProjectId;
|
||||
if (pid != null)
|
||||
{
|
||||
var project = await ProjectService.GetProjectAsync(pid.Value);
|
||||
currentProjectName = project?.Name;
|
||||
}
|
||||
|
||||
await LoadUserSettings();
|
||||
|
||||
try
|
||||
|
|
@ -232,9 +250,9 @@
|
|||
private async Task SwitchUser(ChangeEventArgs e)
|
||||
{
|
||||
var userId = int.Parse(e.Value?.ToString() ?? "0");
|
||||
await SettingsService.SetCurrentUserAsync(userId);
|
||||
selectedUserId = userId;
|
||||
|
||||
SettingsService.SetCurrentUser(userId);
|
||||
await SettingsService.InitializeAsync();
|
||||
await LoadUserSettings();
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +263,7 @@
|
|||
var user = await SettingsService.CreateUserAsync(newUserName);
|
||||
users.Add(user);
|
||||
newUserName = string.Empty;
|
||||
statusMessage = T($"Benutzer '{user.Name}' erstellt.", $"User '{user.Name}' created.");
|
||||
statusMessage = string.Format(Loc["settings.status.user_created"], user.Name);
|
||||
}
|
||||
|
||||
private async Task SaveSettings()
|
||||
|
|
@ -276,7 +294,10 @@
|
|||
await SettingsService.SaveEli5PromptAsync(eli5Prompt);
|
||||
await SettingsService.SaveLanguageAsync(selectedLanguage);
|
||||
|
||||
statusMessage = T("Einstellungen gespeichert.", "Settings saved.");
|
||||
if (selectedLanguage != Loc.CurrentLanguage)
|
||||
await Loc.SetLanguageAsync(selectedLanguage);
|
||||
|
||||
statusMessage = Loc["settings.status.saved"];
|
||||
await ThemeService.ApplyTheme(selectedTheme);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,59 @@
|
|||
@page "/setup-2fa"
|
||||
@inject IAuthService AuthService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISettingsService SettingsService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject ILocalizationService Loc
|
||||
|
||||
@rendermode InteractiveServer
|
||||
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
|
||||
|
||||
<PageTitle>@T("2FA einrichten - Author Buddy", "2FA setup - Author Buddy")</PageTitle>
|
||||
<PageTitle>@Loc["page.title.setup2fa"]</PageTitle>
|
||||
|
||||
<div class="auth-page">
|
||||
<div class="auth-card">
|
||||
<h2>@T("Zwei-Faktor-Authentifizierung", "Two-Factor Authentication")</h2>
|
||||
<div class="auth-logo">
|
||||
<img src="/Assets/logo.jpg" alt="Author Buddy" />
|
||||
</div>
|
||||
<h2>@Loc["setup2fa.heading"]</h2>
|
||||
|
||||
@if (isEnabled)
|
||||
{
|
||||
<div class="auth-success">
|
||||
<p>@T("2FA ist aktiviert.", "2FA is enabled.")</p>
|
||||
<button @onclick="Disable2FA" disabled="@isBusy">@T("2FA deaktivieren", "Disable 2FA")</button>
|
||||
<p>@Loc["setup2fa.status.enabled"]</p>
|
||||
<button @onclick="Disable2FA" disabled="@isBusy">@Loc["setup2fa.button.disable"]</button>
|
||||
</div>
|
||||
}
|
||||
else if (showSecret)
|
||||
{
|
||||
<p>@T("Scanne den folgenden QR-Code mit deiner Authenticator-App (z.B. Google Authenticator, Microsoft Authenticator) oder gib den geheimen Schlüssel manuell ein:", "Scan the QR code below with your authenticator app (e.g. Google Authenticator, Microsoft Authenticator) or enter the secret key manually:")</p>
|
||||
<p>@Loc["setup2fa.instruction"]</p>
|
||||
|
||||
<div class="qr-container">
|
||||
<img src="@qrCodeDataUri" alt="QR Code" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>@T("Geheimer Schlüssel:", "Secret key:")</label>
|
||||
<label>@Loc["setup2fa.label.secret_key"]</label>
|
||||
<div class="secret-display">
|
||||
<code>@secret</code>
|
||||
<button @onclick="CopySecret">@T("Kopieren", "Copy")</button>
|
||||
<button @onclick="CopySecret">@Loc["common.copy"]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="code">@T("Code zur Bestätigung eingeben:", "Enter verification code:")</label>
|
||||
<label for="code">@Loc["setup2fa.label.verification_code"]</label>
|
||||
<input id="code" @bind="verificationCode" maxlength="6" @onkeydown="HandleKeyDown" />
|
||||
</div>
|
||||
|
||||
<div class="auth-actions">
|
||||
<button @onclick="Enable2FA" disabled="@isBusy || string.IsNullOrWhiteSpace(verificationCode)">@T("2FA aktivieren", "Enable 2FA")</button>
|
||||
<button @onclick="Cancel">@T("Abbrechen", "Cancel")</button>
|
||||
<button @onclick="Enable2FA" disabled="@isBusy || string.IsNullOrWhiteSpace(verificationCode)">@Loc["setup2fa.button.enable"]</button>
|
||||
<button @onclick="Cancel">@Loc["common.cancel"]</button>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>@T("Richte die Zwei-Faktor-Authentifizierung ein, um dein Konto zusätzlich zu schützen.", "Set up two-factor authentication to add an extra layer of security to your account.")</p>
|
||||
<p>@Loc["setup2fa.description"]</p>
|
||||
<div class="auth-actions">
|
||||
<button @onclick="StartSetup">@T("2FA einrichten", "Set up 2FA")</button>
|
||||
<button @onclick="StartSetup">@Loc["setup2fa.button.setup"]</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +65,6 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _language = "de";
|
||||
private string secret = string.Empty;
|
||||
private string verificationCode = string.Empty;
|
||||
private string errorMessage = string.Empty;
|
||||
|
|
@ -72,11 +74,8 @@
|
|||
private bool isBusy;
|
||||
private string? username;
|
||||
|
||||
private string T(string de, string en) => _language == "en" ? en : de;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_language = await SettingsService.GetLanguageAsync() ?? "de";
|
||||
isEnabled = await AuthService.Is2FAEnabledAsync();
|
||||
var user = await AuthService.GetCurrentUserAsync();
|
||||
username = user?.Name;
|
||||
|
|
@ -100,7 +99,7 @@
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -112,13 +111,13 @@
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(verificationCode) || verificationCode.Length != 6)
|
||||
{
|
||||
errorMessage = T("Bitte gib einen gültigen 6-stelligen Code ein.", "Please enter a valid 6-digit code.");
|
||||
errorMessage = Loc["setup2fa.error.invalid_code"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TotpHelper.VerifyCode(secret, verificationCode))
|
||||
{
|
||||
errorMessage = T("Code ungültig. Bitte versuche es erneut.", "Invalid code. Please try again.");
|
||||
errorMessage = Loc["setup2fa.error.code_invalid"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -135,12 +134,12 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
errorMessage = T("Fehler beim Aktivieren von 2FA.", "Failed to enable 2FA.");
|
||||
errorMessage = Loc["setup2fa.error.enable_failed"];
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -163,7 +162,7 @@
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"{T("Fehler:", "Error:")} {ex.Message}";
|
||||
errorMessage = $"{Loc["common.error"]} {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
104
Components/Pages/UserManagement.razor
Normal file
104
Components/Pages/UserManagement.razor
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
@page "/user-management"
|
||||
@attribute [Authorize]
|
||||
@inject IAuthService AuthService
|
||||
@inject ILocalizationService Loc
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<PageTitle>@Loc["usermanagement.title"] - Author Buddy</PageTitle>
|
||||
|
||||
<div class="usermanagement-page">
|
||||
<h3>@Loc["usermanagement.title"]</h3>
|
||||
|
||||
<table class="usermanagement-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>@Loc["usermanagement.col.name"]</th>
|
||||
<th>@Loc["usermanagement.col.role"]</th>
|
||||
<th>@Loc["usermanagement.col.status"]</th>
|
||||
<th>@Loc["usermanagement.col.actions"]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var u in users)
|
||||
{
|
||||
<tr class="@(u.Id == currentUserId ? "usermanagement-current" : "") @(!u.IsActive ? "usermanagement-inactive" : "")">
|
||||
<td>@u.Name @(u.Id == currentUserId ? "(Du)" : "")</td>
|
||||
<td>@(u.Role == UserRole.Administrator ? Loc["settings.user.role.admin"] : Loc["settings.user.role.author"])</td>
|
||||
<td>
|
||||
@if (u.IsActive)
|
||||
{
|
||||
<span class="usermanagement-status-active">@Loc["usermanagement.status.active"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="usermanagement-status-inactive">@Loc["usermanagement.status.inactive"]</span>
|
||||
}
|
||||
</td>
|
||||
<td class="usermanagement-actions">
|
||||
@if (u.Id != currentUserId)
|
||||
{
|
||||
@if (u.IsActive)
|
||||
{
|
||||
<button class="btn btn-sm" @onclick="() => DeactivateUser(u.Id)" title="@Loc["usermanagement.action.deactivate"]">@Loc["usermanagement.action.deactivate"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-sm btn-primary" @onclick="() => ActivateUser(u.Id)" title="@Loc["usermanagement.action.activate"]">@Loc["usermanagement.action.activate"]</button>
|
||||
}
|
||||
<button class="btn btn-sm btn-danger" @onclick="() => DeleteUser(u.Id)" title="@Loc["usermanagement.action.delete"]">@Loc["usermanagement.action.delete"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span style="font-size:11px;color:var(--border-color);">@Loc["usermanagement.cannot_self"]</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@if (!string.IsNullOrEmpty(statusMessage))
|
||||
{
|
||||
<div class="usermanagement-status">@statusMessage</div>
|
||||
}
|
||||
|
||||
<button class="btn btn-secondary" @onclick='() => Navigation.NavigateTo("/settings")' style="margin-top:12px;">@Loc["common.back"]</button>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private List<UserEntity> users = new();
|
||||
private int currentUserId;
|
||||
private string statusMessage = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadUsers();
|
||||
}
|
||||
|
||||
private async Task LoadUsers()
|
||||
{
|
||||
users = await AuthService.GetAllUsersAsync();
|
||||
currentUserId = AuthService.CurrentUser?.Id ?? 0;
|
||||
}
|
||||
|
||||
private async Task ActivateUser(int userId)
|
||||
{
|
||||
var ok = await AuthService.SetUserActiveAsync(userId, true);
|
||||
statusMessage = ok ? Loc["usermanagement.status.activated"] : Loc["common.error"];
|
||||
await LoadUsers();
|
||||
}
|
||||
|
||||
private async Task DeactivateUser(int userId)
|
||||
{
|
||||
var ok = await AuthService.SetUserActiveAsync(userId, false);
|
||||
statusMessage = ok ? Loc["usermanagement.status.deactivated"] : Loc["common.error"];
|
||||
await LoadUsers();
|
||||
}
|
||||
|
||||
private async Task DeleteUser(int userId)
|
||||
{
|
||||
var ok = await AuthService.DeleteUserAsync(userId);
|
||||
statusMessage = ok ? Loc["usermanagement.status.deleted"] : Loc["common.error"];
|
||||
await LoadUsers();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,18 @@
|
|||
namespace AuthorBuddy.Web.Data;
|
||||
|
||||
public enum UserRole
|
||||
{
|
||||
Author,
|
||||
Administrator
|
||||
}
|
||||
|
||||
public class UserEntity
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsCurrent { get; set; }
|
||||
public string PasswordHash { get; set; } = string.Empty;
|
||||
public string TwoFactorSecret { get; set; } = string.Empty;
|
||||
public bool TwoFactorEnabled { get; set; }
|
||||
public UserRole Role { get; set; } = UserRole.Author;
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
|
|
|
|||
12
Program.cs
12
Program.cs
|
|
@ -4,6 +4,7 @@ using AuthorBuddy.Web.Services;
|
|||
using LiteDB;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
|
@ -16,12 +17,13 @@ builder.Services.AddSingleton<ILiteDatabase>(new LiteDatabase($"Filename={dbPath
|
|||
builder.Services.AddSingleton<OllamaSettings>();
|
||||
builder.Services.AddSingleton<IOllamaService, OllamaService>();
|
||||
builder.Services.AddSingleton<IFileScannerService, FileScannerService>();
|
||||
builder.Services.AddSingleton<ISettingsService, SettingsService>();
|
||||
builder.Services.AddScoped<ISettingsService, SettingsService>();
|
||||
builder.Services.AddScoped<IThemeService, ThemeService>();
|
||||
builder.Services.AddSingleton<IProjectService, ProjectService>();
|
||||
builder.Services.AddSingleton<IRagService, RagService>();
|
||||
builder.Services.AddSingleton<IWikipediaService, WikipediaService>();
|
||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
builder.Services.AddScoped<ILocalizationService, LocalizationService>();
|
||||
builder.Services.AddScoped<CustomAuthStateProvider>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider>(sp =>
|
||||
sp.GetRequiredService<CustomAuthStateProvider>());
|
||||
|
|
@ -36,8 +38,6 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
|
|||
|
||||
var app = builder.Build();
|
||||
|
||||
var settingsInit = app.Services.GetRequiredService<ISettingsService>();
|
||||
settingsInit.InitializeAsync().GetAwaiter().GetResult();
|
||||
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
|
|
@ -50,6 +50,12 @@ if (!app.Environment.IsDevelopment())
|
|||
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "Assets")),
|
||||
RequestPath = "/Assets"
|
||||
});
|
||||
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
|
|
|||
241
Resources/de.json
Normal file
241
Resources/de.json
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
{
|
||||
"common.status.ready": "Bereit",
|
||||
"common.cancel": "Abbrechen",
|
||||
"common.error": "Fehler:",
|
||||
"common.copy": "Kopieren",
|
||||
"common.status.error": "Fehler",
|
||||
"page.title.login": "Anmelden - Author Buddy",
|
||||
"page.title.register": "Registrieren - Author Buddy",
|
||||
"page.title.setup2fa": "2FA einrichten - Author Buddy",
|
||||
"page.title.settings": "Einstellungen",
|
||||
"page.title.editor": "Editor - Author Buddy",
|
||||
"page.title.assistant": "Assistent - Author Buddy",
|
||||
"page.title.models": "Modelle - Author Buddy",
|
||||
"page.title.home": "Dashboard - Author Buddy",
|
||||
"page.title.error": "Fehler",
|
||||
"page.title.not_found": "Seite nicht gefunden",
|
||||
"nav.menu.file": "Datei",
|
||||
"nav.menu.file.new_project": "Neues Projekt",
|
||||
"nav.menu.file.open_editor": "Editor öffnen",
|
||||
"nav.menu.file.exit": "Beenden",
|
||||
"nav.menu.extras": "Extras",
|
||||
"nav.menu.extras.settings": "Einstellungen",
|
||||
"nav.menu.extras.manage_models": "Modelle verwalten",
|
||||
"nav.menu.extras.assistant": "Assistent",
|
||||
"nav.menu.extras.user_management": "Benutzerverwaltung",
|
||||
"nav.menu.projects": "Projekte",
|
||||
"nav.projects.list_title": "Liste vorhandener Projekte",
|
||||
"nav.projects.loading": "Lade Projekte...",
|
||||
"nav.projects.empty": "Keine Projekte vorhanden.",
|
||||
"nav.projects.create": "Projekt erstellen",
|
||||
"nav.projects.files": "Projektdateien",
|
||||
"nav.projects.refresh_tree": "Dateibaum aktualisieren",
|
||||
"nav.projects.file.new": "Neue Datei",
|
||||
"nav.projects.file.rename": "Umbenennen",
|
||||
"nav.rename.title": "Datei umbenennen",
|
||||
"nav.rename.label.new_name": "Neuer Name",
|
||||
"nav.rename.placeholder": "neuer_name.md",
|
||||
"nav.rename.button.confirm": "Umbenennen",
|
||||
"nav.newfile.title": "Neue Datei",
|
||||
"nav.newfile.label.filename": "Dateiname",
|
||||
"nav.newfile.placeholder": "meine_datei.md",
|
||||
"nav.newfile.button.create": "Erstellen",
|
||||
"nav.user.logged_in_as": "Angemeldet als:",
|
||||
"nav.user.manage_2fa": "2FA verwalten",
|
||||
"nav.user.logout": "Abmelden",
|
||||
"nav.error.file_exists": "Datei existiert bereits.",
|
||||
"nav.projects.copy": "Projekt kopieren",
|
||||
"nav.copy_project.title": "Projekt kopieren",
|
||||
"nav.copy_project.label.name": "Neuer Projektname:",
|
||||
"nav.copy_project.placeholder.name": "z.B. Mein Roman (Kopie)",
|
||||
"nav.copy_project.label.path": "Zielpfad:",
|
||||
"nav.copy_project.placeholder.path": "z.B. C:\\Projekte\\MeinRomanKopie",
|
||||
"nav.copy_project.button.copy": "Kopieren",
|
||||
"nav.status.project_copied": "Projekt kopiert:",
|
||||
"nav.status.renamed_to": "Umbenannt zu:",
|
||||
"nav.status.created": "Erstellt:",
|
||||
"login.heading": "Anmelden",
|
||||
"login.label.username": "Benutzername:",
|
||||
"login.label.password": "Passwort:",
|
||||
"login.button.submit": "Anmelden",
|
||||
"login.link.register": "Registrieren",
|
||||
"login.2fa.instruction": "Gib den 6-stelligen Code aus deiner Authenticator-App ein:",
|
||||
"login.2fa.label.code": "2FA-Code:",
|
||||
"login.2fa.button.verify": "Bestätigen",
|
||||
"login.error.empty_fields": "Bitte Benutzername und Passwort eingeben.",
|
||||
"login.error.invalid_credentials": "Benutzername oder Passwort falsch.",
|
||||
"login.2fa.error.invalid_code": "Bitte gib einen gültigen 6-stelligen Code ein.",
|
||||
"login.2fa.error.code_failed": "Ungültiger Code. Bitte versuche es erneut.",
|
||||
"register.heading": "Registrieren",
|
||||
"register.label.username": "Benutzername:",
|
||||
"register.label.password": "Passwort:",
|
||||
"register.label.confirm_password": "Passwort bestätigen:",
|
||||
"register.button.submit": "Registrieren",
|
||||
"register.link.back_to_login": "Zurück zum Login",
|
||||
"register.error.no_username": "Bitte Benutzername eingeben.",
|
||||
"register.error.no_password": "Bitte Passwort eingeben.",
|
||||
"register.error.password_mismatch": "Passwörter stimmen nicht überein.",
|
||||
"register.error.password_too_short": "Passwort muss mindestens 4 Zeichen lang sein.",
|
||||
"register.error.username_taken": "Benutzername ist bereits vergeben.",
|
||||
"setup2fa.heading": "Zwei-Faktor-Authentifizierung",
|
||||
"setup2fa.status.enabled": "2FA ist aktiviert.",
|
||||
"setup2fa.button.disable": "2FA deaktivieren",
|
||||
"setup2fa.instruction": "Scanne den folgenden QR-Code mit deiner Authenticator-App (z.B. Google Authenticator, Microsoft Authenticator) oder gib den geheimen Schlüssel manuell ein:",
|
||||
"setup2fa.label.secret_key": "Geheimer Schlüssel:",
|
||||
"setup2fa.label.verification_code": "Code zur Bestätigung eingeben:",
|
||||
"setup2fa.button.enable": "2FA aktivieren",
|
||||
"setup2fa.description": "Richte die Zwei-Faktor-Authentifizierung ein, um dein Konto zusätzlich zu schützen.",
|
||||
"setup2fa.button.setup": "2FA einrichten",
|
||||
"setup2fa.error.invalid_code": "Bitte gib einen gültigen 6-stelligen Code ein.",
|
||||
"setup2fa.error.code_invalid": "Code ungültig. Bitte versuche es erneut.",
|
||||
"setup2fa.error.enable_failed": "Fehler beim Aktivieren von 2FA.",
|
||||
"settings.context.project": "Projekt-Einstellungen für",
|
||||
"settings.context.user": "Allgemeine Benutzer-Einstellungen",
|
||||
"settings.section.user": "Benutzer",
|
||||
"settings.user.label.active": "Aktiver Benutzer:",
|
||||
"settings.user.label.new": "Neuer Benutzer:",
|
||||
"settings.user.placeholder.name": "Name",
|
||||
"settings.user.button.add": "Hinzufügen",
|
||||
"settings.user.role.admin": "Administrator",
|
||||
"settings.user.role.author": "Autor",
|
||||
"settings.user.link.2fa": "2FA einrichten",
|
||||
"settings.section.models": "Modelle",
|
||||
"settings.models.label.rag": "RAG-Modell (Faktenabfrage):",
|
||||
"settings.models.empty": "Keine Modelle gefunden",
|
||||
"settings.models.label.style": "Stil-Modell (Lektorat):",
|
||||
"settings.models.label.spellcheck": "Rechtschreibprüfungs-Modell:",
|
||||
"settings.section.ollama_server": "Ollama Server",
|
||||
"settings.ollama.label.url": "Server-URL:",
|
||||
"settings.ollama.hint.url": "Adresse des Ollama-Servers",
|
||||
"settings.section.appearance": "Design",
|
||||
"settings.appearance.label.theme": "Theme:",
|
||||
"settings.appearance.theme.light": "Hell",
|
||||
"settings.appearance.theme.dark": "Dunkel",
|
||||
"settings.appearance.theme.retro": "(Retro)",
|
||||
"settings.section.language": "Sprache",
|
||||
"settings.language.label": "Sprache:",
|
||||
"settings.section.editor_prompt": "Lektor-System-Prompt",
|
||||
"settings.section.factcheck_template": "Fact-Check-Vorlage",
|
||||
"settings.section.spellcheck_prompt": "Rechtschreibprüfungs-Prompt",
|
||||
"settings.section.advocatus_diaboli": "Advocatus Diaboli",
|
||||
"settings.section.hook_finder": "Hook-Finder",
|
||||
"settings.section.eli5": "ELI5-Vereinfachung",
|
||||
"settings.button.save": "Speichern",
|
||||
"settings.status.user_created": "Benutzer '{0}' erstellt.",
|
||||
"settings.status.saved": "Einstellungen gespeichert.",
|
||||
"assistant.mode.lektorat": "Lektorat",
|
||||
"assistant.mode.advocatus": "Advocatus Diaboli",
|
||||
"assistant.mode.hookfinder": "Hook-Finder",
|
||||
"assistant.mode.eli5": "ELI5-Vereinfachung",
|
||||
"assistant.button.execute": "Ausführen",
|
||||
"assistant.button.send_to_editor": "An Editor übermitteln",
|
||||
"assistant.label.input_text": "Eingabetext",
|
||||
"assistant.placeholder.input": "Füge hier deinen Text ein...",
|
||||
"assistant.label.result": "Ergebnis",
|
||||
"assistant.hint.empty_result": "Ergebnis erscheint hier nach der Ausführung.",
|
||||
"assistant.status.processing": "Verarbeite...",
|
||||
"assistant.error.no_prompt": "Kein System-Prompt für diesen Modus konfiguriert. Bitte in den Einstellungen hinterlegen.",
|
||||
"assistant.status.done": "Fertig.",
|
||||
"models.heading": "Ollama Modelle verwalten",
|
||||
"models.button.refresh": "Aktualisieren",
|
||||
"models.status.loading": "Lade Modelle...",
|
||||
"models.label.size": "Größe:",
|
||||
"models.label.modified": "Geändert:",
|
||||
"models.pull.heading": "Neues Modell herunterladen",
|
||||
"models.pull.label.name": "Modellname:",
|
||||
"models.pull.placeholder": "z.B. llama3.2",
|
||||
"models.pull.button.download": "Herunterladen",
|
||||
"models.error.loading": "Fehler beim Laden der Modelle:",
|
||||
"models.pull.status.starting": "Starte Download...",
|
||||
"models.pull.status.model": "Modell",
|
||||
"models.pull.status.success": "erfolgreich heruntergeladen.",
|
||||
"editor.status.autosaved": "Automatisch gespeichert.",
|
||||
"editor.status.corrections_applied": "Korrekturen übernommen.",
|
||||
"editor.spellcheck.button.apply": "Korrekturen übernehmen",
|
||||
"editor.version.button.browse": "Versionen",
|
||||
"editor.version.button.diff": "Vergleichen",
|
||||
"editor.version.button.restore": "Wiederherstellen",
|
||||
"editor.version.list_title": "Vorhandene Versionen",
|
||||
"editor.version.diff_title": "Diff: Version vom",
|
||||
"editor.version.empty": "Keine Versionen vorhanden.",
|
||||
"editor.placeholder.content": "Schreibe hier deinen Text...",
|
||||
"editor.button.style_check": "Stil prüfen",
|
||||
"editor.button.spell_check": "Rechtschreibung prüfen",
|
||||
"editor.button.save": "Speichern",
|
||||
"editor.button.version": "Version",
|
||||
"editor.button.assistant": "Assistent",
|
||||
"editor.button.index_project": "Projekt indexieren",
|
||||
"editor.version.title": "Version speichern",
|
||||
"editor.version.label.comment": "Kommentar (optional)",
|
||||
"editor.version.placeholder.comment": "Was hat sich geändert?",
|
||||
"editor.version.button.save": "Version speichern",
|
||||
"editor.search.placeholder": "Suchbegriff für Fakten-/Wikipedia-Recherche...",
|
||||
"editor.button.search_rag": "Fakten suchen (RAG)",
|
||||
"editor.button.search_wikipedia": "Wikipedia-Recherche",
|
||||
"editor.spellcheck.heading": "Rechtschreibprüfung - Änderungen:",
|
||||
"editor.rag.heading": "Gefundene Fakten (RAG):",
|
||||
"editor.rag.label.similarity": "Ähnlichkeit:",
|
||||
"editor.wikipedia.heading": "Wikipedia-Recherche:",
|
||||
"editor.wikipedia.status.loaded": "✓ Geladen",
|
||||
"editor.wikipedia.button.load": "Vollständigen Artikel laden",
|
||||
"editor.wikipedia.button.save_as_fact": "Als Fakt speichern",
|
||||
"editor.result.heading": "Ergebnis:",
|
||||
"editor.create_project.title": "Neues Projekt erstellen",
|
||||
"editor.create_project.label.name": "Projektname",
|
||||
"editor.create_project.placeholder.name": "z.B. Mein Roman",
|
||||
"editor.create_project.label.path": "Projektpfad",
|
||||
"editor.create_project.placeholder.path": "z.B. C:\\Projekte\\MeinRoman",
|
||||
"editor.button.create": "Erstellen",
|
||||
"editor.status.imported_from_assistant": "Text aus Assistent übernommen.",
|
||||
"editor.status.loaded": "Geladen:",
|
||||
"editor.status.analyzing_style": "Ollama analysiert Stil...",
|
||||
"editor.status.checking_spelling": "Ollama prüft Rechtschreibung...",
|
||||
"editor.status.searching_rag": "Suche verwandte Fakten...",
|
||||
"editor.status.searching_wikipedia": "Suche auf Wikipedia...",
|
||||
"editor.status.loading_article": "Lade Artikel:",
|
||||
"editor.status.saving_fact": "Speichere als Fakt...",
|
||||
"editor.status.creating_project": "Erstelle Projekt...",
|
||||
"editor.status.indexing": "Indexiere Projekt...",
|
||||
"editor.status.saved": "Gespeichert:",
|
||||
"editor.status.version_saved": "Version gespeichert:",
|
||||
"editor.status.saved_as": "Gespeichert als:",
|
||||
"editor.rag.error.no_project": "Kein Projekt geladen. Öffne zuerst ein Projekt über die Sidebar.",
|
||||
"editor.rag.error.no_facts": "Keine relevanten Fakten gefunden. Indexiere das Projekt ggf. über 'Projekt indexieren'.",
|
||||
"editor.rag.error.generic": "RAG-Fehler:",
|
||||
"editor.wikipedia.error.not_found": "Keine Wikipedia-Artikel gefunden.",
|
||||
"editor.wikipedia.error.generic": "Wikipedia-Fehler:",
|
||||
"editor.wikipedia.error.load_failed": "Konnte Artikel nicht laden.",
|
||||
"editor.error.project_not_found": "Projekt nicht gefunden.",
|
||||
"editor.error.save_failed": "Fehler beim Speichern:",
|
||||
"editor.error.create_failed": "Fehler beim Erstellen:",
|
||||
"editor.index.error.no_project": "Kein Projekt geladen. Öffne zuerst ein Projekt über die Sidebar.",
|
||||
"editor.index.error.not_found": "Projekt nicht gefunden.",
|
||||
"editor.index.status.success": "Projekt erfolgreich indexiert.",
|
||||
"editor.index.error.generic": "Indexierungsfehler:",
|
||||
"editor.version.status_loaded_prefix": "Version vom",
|
||||
"editor.version.status_loaded_suffix": "geladen.",
|
||||
"home.tab.rag_facts": "Gefundene Fakten (RAG)",
|
||||
"home.tab.style_analysis": "Stil-Analyse",
|
||||
"home.rag.empty": "Keine Fakten gefunden. Öffne ein Projekt und scanne die Dateien.",
|
||||
"error.heading": "Ein Fehler ist aufgetreten",
|
||||
"error.message": "Entschuldigung, es ist ein unerwarteter Fehler aufgetreten.",
|
||||
"error.link.back_to_home": "Zurück zur Startseite",
|
||||
"notfound.heading": "404 - Seite nicht gefunden",
|
||||
"notfound.message": "Die angeforderte Seite existiert nicht.",
|
||||
"notfound.link.back_to_home": "Zurück zur Startseite",
|
||||
"usermanagement.title": "Benutzerverwaltung",
|
||||
"usermanagement.col.name": "Name",
|
||||
"usermanagement.col.role": "Rolle",
|
||||
"usermanagement.col.status": "Status",
|
||||
"usermanagement.col.actions": "Aktionen",
|
||||
"usermanagement.status.active": "Aktiv",
|
||||
"usermanagement.status.inactive": "Deaktiviert",
|
||||
"usermanagement.action.activate": "Freischalten",
|
||||
"usermanagement.action.deactivate": "Deaktivieren",
|
||||
"usermanagement.action.delete": "Löschen",
|
||||
"usermanagement.cannot_self": "Kann sich nicht selbst verwalten",
|
||||
"usermanagement.status.activated": "Benutzer freigeschaltet.",
|
||||
"usermanagement.status.deactivated": "Benutzer deaktiviert.",
|
||||
"usermanagement.status.deleted": "Benutzer gelöscht.",
|
||||
"common.back": "Zurück"
|
||||
}
|
||||
241
Resources/en.json
Normal file
241
Resources/en.json
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
{
|
||||
"common.status.ready": "Ready",
|
||||
"common.cancel": "Cancel",
|
||||
"common.error": "Error:",
|
||||
"common.copy": "Copy",
|
||||
"common.status.error": "Error",
|
||||
"page.title.login": "Login - Author Buddy",
|
||||
"page.title.register": "Register - Author Buddy",
|
||||
"page.title.setup2fa": "2FA setup - Author Buddy",
|
||||
"page.title.settings": "Settings",
|
||||
"page.title.editor": "Editor - Author Buddy",
|
||||
"page.title.assistant": "Assistant - Author Buddy",
|
||||
"page.title.models": "Models - Author Buddy",
|
||||
"page.title.home": "Dashboard - Author Buddy",
|
||||
"page.title.error": "Error",
|
||||
"page.title.not_found": "Page not found",
|
||||
"nav.menu.file": "File",
|
||||
"nav.menu.file.new_project": "New project",
|
||||
"nav.menu.file.open_editor": "Open editor",
|
||||
"nav.menu.file.exit": "Exit",
|
||||
"nav.menu.extras": "Extras",
|
||||
"nav.menu.extras.settings": "Settings",
|
||||
"nav.menu.extras.manage_models": "Manage models",
|
||||
"nav.menu.extras.assistant": "Assistant",
|
||||
"nav.menu.extras.user_management": "User management",
|
||||
"nav.menu.projects": "Projects",
|
||||
"nav.projects.list_title": "List existing projects",
|
||||
"nav.projects.loading": "Loading projects...",
|
||||
"nav.projects.empty": "No projects available.",
|
||||
"nav.projects.create": "Create project",
|
||||
"nav.projects.files": "Project files",
|
||||
"nav.projects.refresh_tree": "Refresh file tree",
|
||||
"nav.projects.file.new": "New file",
|
||||
"nav.projects.file.rename": "Rename",
|
||||
"nav.rename.title": "Rename file",
|
||||
"nav.rename.label.new_name": "New name",
|
||||
"nav.rename.placeholder": "new_name.md",
|
||||
"nav.rename.button.confirm": "Rename",
|
||||
"nav.newfile.title": "New file",
|
||||
"nav.newfile.label.filename": "Filename",
|
||||
"nav.newfile.placeholder": "my_file.md",
|
||||
"nav.newfile.button.create": "Create",
|
||||
"nav.user.logged_in_as": "Logged in as:",
|
||||
"nav.user.manage_2fa": "Manage 2FA",
|
||||
"nav.user.logout": "Logout",
|
||||
"nav.error.file_exists": "File already exists.",
|
||||
"nav.projects.copy": "Copy project",
|
||||
"nav.copy_project.title": "Copy project",
|
||||
"nav.copy_project.label.name": "New project name:",
|
||||
"nav.copy_project.placeholder.name": "e.g. My novel (Copy)",
|
||||
"nav.copy_project.label.path": "Destination path:",
|
||||
"nav.copy_project.placeholder.path": "e.g. C:\\Projects\\MyNovelCopy",
|
||||
"nav.copy_project.button.copy": "Copy",
|
||||
"nav.status.project_copied": "Project copied:",
|
||||
"nav.status.renamed_to": "Renamed to:",
|
||||
"nav.status.created": "Created:",
|
||||
"login.heading": "Login",
|
||||
"login.label.username": "Username:",
|
||||
"login.label.password": "Password:",
|
||||
"login.button.submit": "Login",
|
||||
"login.link.register": "Register",
|
||||
"login.2fa.instruction": "Enter the 6-digit code from your authenticator app:",
|
||||
"login.2fa.label.code": "2FA code:",
|
||||
"login.2fa.button.verify": "Verify",
|
||||
"login.error.empty_fields": "Please enter username and password.",
|
||||
"login.error.invalid_credentials": "Invalid username or password.",
|
||||
"login.2fa.error.invalid_code": "Please enter a valid 6-digit code.",
|
||||
"login.2fa.error.code_failed": "Invalid code. Please try again.",
|
||||
"register.heading": "Register",
|
||||
"register.label.username": "Username:",
|
||||
"register.label.password": "Password:",
|
||||
"register.label.confirm_password": "Confirm password:",
|
||||
"register.button.submit": "Register",
|
||||
"register.link.back_to_login": "Back to login",
|
||||
"register.error.no_username": "Please enter a username.",
|
||||
"register.error.no_password": "Please enter a password.",
|
||||
"register.error.password_mismatch": "Passwords do not match.",
|
||||
"register.error.password_too_short": "Password must be at least 4 characters long.",
|
||||
"register.error.username_taken": "Username is already taken.",
|
||||
"setup2fa.heading": "Two-Factor Authentication",
|
||||
"setup2fa.status.enabled": "2FA is enabled.",
|
||||
"setup2fa.button.disable": "Disable 2FA",
|
||||
"setup2fa.instruction": "Scan the QR code below with your authenticator app (e.g. Google Authenticator, Microsoft Authenticator) or enter the secret key manually:",
|
||||
"setup2fa.label.secret_key": "Secret key:",
|
||||
"setup2fa.label.verification_code": "Enter verification code:",
|
||||
"setup2fa.button.enable": "Enable 2FA",
|
||||
"setup2fa.description": "Set up two-factor authentication to add an extra layer of security to your account.",
|
||||
"setup2fa.button.setup": "Set up 2FA",
|
||||
"setup2fa.error.invalid_code": "Please enter a valid 6-digit code.",
|
||||
"setup2fa.error.code_invalid": "Invalid code. Please try again.",
|
||||
"setup2fa.error.enable_failed": "Failed to enable 2FA.",
|
||||
"settings.context.project": "Project settings for",
|
||||
"settings.context.user": "General user settings",
|
||||
"settings.section.user": "User",
|
||||
"settings.user.label.active": "Active user:",
|
||||
"settings.user.label.new": "New user:",
|
||||
"settings.user.placeholder.name": "Name",
|
||||
"settings.user.button.add": "Add",
|
||||
"settings.user.role.admin": "Administrator",
|
||||
"settings.user.role.author": "Author",
|
||||
"settings.user.link.2fa": "Set up 2FA",
|
||||
"settings.section.models": "Models",
|
||||
"settings.models.label.rag": "RAG model (facts):",
|
||||
"settings.models.empty": "No models found",
|
||||
"settings.models.label.style": "Style model (editing):",
|
||||
"settings.models.label.spellcheck": "Spell check model:",
|
||||
"settings.section.ollama_server": "Ollama Server",
|
||||
"settings.ollama.label.url": "Server URL:",
|
||||
"settings.ollama.hint.url": "Ollama server address",
|
||||
"settings.section.appearance": "Appearance",
|
||||
"settings.appearance.label.theme": "Theme:",
|
||||
"settings.appearance.theme.light": "Light",
|
||||
"settings.appearance.theme.dark": "Dark",
|
||||
"settings.appearance.theme.retro": "(Retro)",
|
||||
"settings.section.language": "Language",
|
||||
"settings.language.label": "Language:",
|
||||
"settings.section.editor_prompt": "Editor system prompt",
|
||||
"settings.section.factcheck_template": "Fact check template",
|
||||
"settings.section.spellcheck_prompt": "Spell check prompt",
|
||||
"settings.section.advocatus_diaboli": "Advocatus Diaboli",
|
||||
"settings.section.hook_finder": "Hook finder",
|
||||
"settings.section.eli5": "ELI5-Simplification",
|
||||
"settings.button.save": "Save",
|
||||
"settings.status.user_created": "User '{0}' created.",
|
||||
"settings.status.saved": "Settings saved.",
|
||||
"assistant.mode.lektorat": "Editing",
|
||||
"assistant.mode.advocatus": "Advocatus Diaboli",
|
||||
"assistant.mode.hookfinder": "Hook finder",
|
||||
"assistant.mode.eli5": "ELI5 simplification",
|
||||
"assistant.button.execute": "Execute",
|
||||
"assistant.button.send_to_editor": "Send to editor",
|
||||
"assistant.label.input_text": "Input text",
|
||||
"assistant.placeholder.input": "Paste your text here...",
|
||||
"assistant.label.result": "Result",
|
||||
"assistant.hint.empty_result": "Result appears here after execution.",
|
||||
"assistant.status.processing": "Processing...",
|
||||
"assistant.error.no_prompt": "No system prompt configured for this mode. Please configure in settings.",
|
||||
"assistant.status.done": "Done.",
|
||||
"models.heading": "Manage Ollama models",
|
||||
"models.button.refresh": "Refresh",
|
||||
"models.status.loading": "Loading models...",
|
||||
"models.label.size": "Size:",
|
||||
"models.label.modified": "Modified:",
|
||||
"models.pull.heading": "Download new model",
|
||||
"models.pull.label.name": "Model name:",
|
||||
"models.pull.placeholder": "e.g. llama3.2",
|
||||
"models.pull.button.download": "Download",
|
||||
"models.error.loading": "Error loading models:",
|
||||
"models.pull.status.starting": "Starting download...",
|
||||
"models.pull.status.model": "Model",
|
||||
"models.pull.status.success": "downloaded successfully.",
|
||||
"editor.status.autosaved": "Auto-saved.",
|
||||
"editor.status.corrections_applied": "Corrections applied.",
|
||||
"editor.spellcheck.button.apply": "Apply corrections",
|
||||
"editor.version.button.browse": "Versions",
|
||||
"editor.version.button.diff": "Compare",
|
||||
"editor.version.button.restore": "Restore",
|
||||
"editor.version.list_title": "Available versions",
|
||||
"editor.version.diff_title": "Diff: version from",
|
||||
"editor.version.empty": "No versions available.",
|
||||
"editor.placeholder.content": "Write your text here...",
|
||||
"editor.button.style_check": "Check style",
|
||||
"editor.button.spell_check": "Spell check",
|
||||
"editor.button.save": "Save",
|
||||
"editor.button.version": "Version",
|
||||
"editor.button.assistant": "Assistant",
|
||||
"editor.button.index_project": "Index project",
|
||||
"editor.version.title": "Save version",
|
||||
"editor.version.label.comment": "Comment (optional)",
|
||||
"editor.version.placeholder.comment": "What changed?",
|
||||
"editor.version.button.save": "Save version",
|
||||
"editor.search.placeholder": "Search term for fact/Wikipedia research...",
|
||||
"editor.button.search_rag": "Search facts (RAG)",
|
||||
"editor.button.search_wikipedia": "Wikipedia research",
|
||||
"editor.spellcheck.heading": "Spell check - Changes:",
|
||||
"editor.rag.heading": "Found facts (RAG):",
|
||||
"editor.rag.label.similarity": "Similarity:",
|
||||
"editor.wikipedia.heading": "Wikipedia research:",
|
||||
"editor.wikipedia.status.loaded": "\u2713 Loaded",
|
||||
"editor.wikipedia.button.load": "Load full article",
|
||||
"editor.wikipedia.button.save_as_fact": "Save as fact",
|
||||
"editor.result.heading": "Result:",
|
||||
"editor.create_project.title": "Create new project",
|
||||
"editor.create_project.label.name": "Project name",
|
||||
"editor.create_project.placeholder.name": "e.g. My novel",
|
||||
"editor.create_project.label.path": "Project path",
|
||||
"editor.create_project.placeholder.path": "e.g. C:\\Projects\\MyNovel",
|
||||
"editor.button.create": "Create",
|
||||
"editor.status.imported_from_assistant": "Text imported from assistant.",
|
||||
"editor.status.loaded": "Loaded:",
|
||||
"editor.status.analyzing_style": "Ollama analyzing style...",
|
||||
"editor.status.checking_spelling": "Ollama checking spelling...",
|
||||
"editor.status.searching_rag": "Searching related facts...",
|
||||
"editor.status.searching_wikipedia": "Searching Wikipedia...",
|
||||
"editor.status.loading_article": "Loading article:",
|
||||
"editor.status.saving_fact": "Saving as fact...",
|
||||
"editor.status.creating_project": "Creating project...",
|
||||
"editor.status.indexing": "Indexing project...",
|
||||
"editor.status.saved": "Saved:",
|
||||
"editor.status.version_saved": "Version saved:",
|
||||
"editor.status.saved_as": "Saved as:",
|
||||
"editor.rag.error.no_project": "No project loaded. Open a project via the sidebar first.",
|
||||
"editor.rag.error.no_facts": "No relevant facts found. Index the project if needed via 'Index project'.",
|
||||
"editor.rag.error.generic": "RAG error:",
|
||||
"editor.wikipedia.error.not_found": "No Wikipedia articles found.",
|
||||
"editor.wikipedia.error.generic": "Wikipedia error:",
|
||||
"editor.wikipedia.error.load_failed": "Could not load article.",
|
||||
"editor.error.project_not_found": "Project not found.",
|
||||
"editor.error.save_failed": "Error saving:",
|
||||
"editor.error.create_failed": "Error creating:",
|
||||
"editor.index.error.no_project": "No project loaded. Open a project via the sidebar first.",
|
||||
"editor.index.error.not_found": "Project not found.",
|
||||
"editor.index.status.success": "Project indexed successfully.",
|
||||
"editor.index.error.generic": "Indexing error:",
|
||||
"editor.version.status_loaded_prefix": "Version from",
|
||||
"editor.version.status_loaded_suffix": "loaded.",
|
||||
"home.tab.rag_facts": "Found facts (RAG)",
|
||||
"home.tab.style_analysis": "Style analysis",
|
||||
"home.rag.empty": "No facts found. Open a project and scan the files.",
|
||||
"error.heading": "An error occurred",
|
||||
"error.message": "Sorry, an unexpected error occurred.",
|
||||
"error.link.back_to_home": "Back to home",
|
||||
"notfound.heading": "404 - Page not found",
|
||||
"notfound.message": "The requested page does not exist.",
|
||||
"notfound.link.back_to_home": "Back to home",
|
||||
"usermanagement.title": "User management",
|
||||
"usermanagement.col.name": "Name",
|
||||
"usermanagement.col.role": "Role",
|
||||
"usermanagement.col.status": "Status",
|
||||
"usermanagement.col.actions": "Actions",
|
||||
"usermanagement.status.active": "Active",
|
||||
"usermanagement.status.inactive": "Disabled",
|
||||
"usermanagement.action.activate": "Activate",
|
||||
"usermanagement.action.deactivate": "Deactivate",
|
||||
"usermanagement.action.delete": "Delete",
|
||||
"usermanagement.cannot_self": "Cannot manage yourself",
|
||||
"usermanagement.status.activated": "User activated.",
|
||||
"usermanagement.status.deactivated": "User deactivated.",
|
||||
"usermanagement.status.deleted": "User deleted.",
|
||||
"common.back": "Back"
|
||||
}
|
||||
|
|
@ -7,18 +7,21 @@ public class AuthService : IAuthService
|
|||
{
|
||||
private readonly ILiteDatabase _db;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILocalizationService _loc;
|
||||
private UserEntity? _currentUser;
|
||||
private string? _pending2FASecret;
|
||||
private bool _requires2FA;
|
||||
|
||||
public AuthService(ILiteDatabase db, ISettingsService settingsService)
|
||||
public AuthService(ILiteDatabase db, ISettingsService settingsService, ILocalizationService loc)
|
||||
{
|
||||
_db = db;
|
||||
_settingsService = settingsService;
|
||||
_loc = loc;
|
||||
}
|
||||
|
||||
public bool IsLoggedIn => _currentUser != null;
|
||||
public bool Is2FARequired => _requires2FA;
|
||||
public UserEntity? CurrentUser => _currentUser;
|
||||
|
||||
public async Task<bool> LoginAsync(string username, string password)
|
||||
{
|
||||
|
|
@ -28,6 +31,9 @@ public class AuthService : IAuthService
|
|||
if (user == null || string.IsNullOrEmpty(user.PasswordHash))
|
||||
return false;
|
||||
|
||||
if (!user.IsActive)
|
||||
return false;
|
||||
|
||||
if (!TotpHelper.VerifyPassword(password, user.PasswordHash))
|
||||
return false;
|
||||
|
||||
|
|
@ -64,13 +70,14 @@ public class AuthService : IAuthService
|
|||
var existing = col.FindOne(u => u.Name == username);
|
||||
if (existing != null) return false;
|
||||
|
||||
var hasUsers = col.FindAll().Any();
|
||||
var user = new UserEntity
|
||||
{
|
||||
Name = username,
|
||||
PasswordHash = TotpHelper.HashPassword(password),
|
||||
IsCurrent = true,
|
||||
TwoFactorEnabled = false,
|
||||
TwoFactorSecret = string.Empty
|
||||
TwoFactorSecret = string.Empty,
|
||||
Role = hasUsers ? UserRole.Author : UserRole.Administrator
|
||||
};
|
||||
col.Insert(user);
|
||||
await SetAuthenticatedUser(user);
|
||||
|
|
@ -162,15 +169,42 @@ public class AuthService : IAuthService
|
|||
_pending2FASecret = null;
|
||||
_settingsService.CurrentProjectId = null;
|
||||
_settingsService.CurrentFilePath = null;
|
||||
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var all = col.FindAll().ToList();
|
||||
foreach (var u in all)
|
||||
{
|
||||
u.IsCurrent = u.Id == user.Id;
|
||||
col.Update(u);
|
||||
}
|
||||
_settingsService.SetCurrentUser(user.Id);
|
||||
|
||||
await _settingsService.InitializeAsync();
|
||||
await _loc.InitAsync();
|
||||
}
|
||||
|
||||
public Task<List<UserEntity>> GetAllUsersAsync()
|
||||
{
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
return Task.FromResult(col.FindAll().OrderBy(u => u.Name).ToList());
|
||||
}
|
||||
|
||||
public async Task<bool> SetUserActiveAsync(int userId, bool active)
|
||||
{
|
||||
if (_currentUser != null && userId == _currentUser.Id)
|
||||
return false;
|
||||
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var user = col.FindById(userId);
|
||||
if (user == null) return false;
|
||||
|
||||
user.IsActive = active;
|
||||
col.Update(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteUserAsync(int userId)
|
||||
{
|
||||
if (_currentUser != null && userId == _currentUser.Id)
|
||||
return false;
|
||||
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var user = col.FindById(userId);
|
||||
if (user == null) return false;
|
||||
|
||||
col.Delete(userId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,4 +18,8 @@ public interface IAuthService
|
|||
Task<bool> Disable2FAAsync();
|
||||
Task<bool> Is2FAEnabledAsync();
|
||||
Task<string?> GetCurrent2FASecretAsync();
|
||||
Task<List<UserEntity>> GetAllUsersAsync();
|
||||
Task<bool> SetUserActiveAsync(int userId, bool active);
|
||||
Task<bool> DeleteUserAsync(int userId);
|
||||
UserEntity? CurrentUser { get; }
|
||||
}
|
||||
|
|
|
|||
10
Services/ILocalizationService.cs
Normal file
10
Services/ILocalizationService.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace AuthorBuddy.Web.Services;
|
||||
|
||||
public interface ILocalizationService
|
||||
{
|
||||
string this[string key] { get; }
|
||||
string Get(string key);
|
||||
Task InitAsync();
|
||||
Task SetLanguageAsync(string language);
|
||||
string CurrentLanguage { get; }
|
||||
}
|
||||
|
|
@ -9,4 +9,5 @@ public interface IProjectService
|
|||
Task<Project?> GetProjectAsync(int projectId);
|
||||
Task<List<FileTreeItem>> GetProjectFileTreeAsync(int projectId);
|
||||
Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress);
|
||||
Task<int> CopyProjectAsync(int sourceProjectId, string newName, string newRootPath, int userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public interface ISettingsService
|
|||
|
||||
Task<List<UserEntity>> GetUsersAsync();
|
||||
Task<UserEntity> GetCurrentUserAsync();
|
||||
Task SetCurrentUserAsync(int userId);
|
||||
void SetCurrentUser(int userId);
|
||||
Task<UserEntity> CreateUserAsync(string name);
|
||||
|
||||
int? CurrentProjectId { get; set; }
|
||||
|
|
@ -44,5 +44,5 @@ public interface ISettingsService
|
|||
Task SaveLastProjectIdAsync(int projectId);
|
||||
Task LoadProjectSettingsAsync();
|
||||
|
||||
Task InitializeAsync(int projectId = -1);
|
||||
Task InitializeAsync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@ namespace AuthorBuddy.Web.Services;
|
|||
public interface IThemeService
|
||||
{
|
||||
Task ApplyTheme(string theme);
|
||||
|
||||
string Theme { get; }
|
||||
}
|
||||
|
|
|
|||
119
Services/LocalizationService.cs
Normal file
119
Services/LocalizationService.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace AuthorBuddy.Web.Services;
|
||||
|
||||
public class LocalizationService : ILocalizationService
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
private Dictionary<string, string> _translations = new();
|
||||
private string _language = "de";
|
||||
|
||||
public string CurrentLanguage => _language;
|
||||
|
||||
public LocalizationService(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
}
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_language = await _settingsService.GetLanguageAsync() ?? "de";
|
||||
}
|
||||
catch
|
||||
{
|
||||
_language = "de";
|
||||
}
|
||||
await LoadLanguageInternalAsync(_language);
|
||||
}
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
if (_translations.TryGetValue(key, out var value))
|
||||
return value;
|
||||
return Fallback(key);
|
||||
}
|
||||
|
||||
public string this[string key] => Get(key);
|
||||
|
||||
public async Task SetLanguageAsync(string language)
|
||||
{
|
||||
_language = language;
|
||||
await LoadLanguageInternalAsync(language);
|
||||
}
|
||||
|
||||
private async Task LoadLanguageInternalAsync(string language)
|
||||
{
|
||||
var searched = new List<string>();
|
||||
|
||||
var paths = new[]
|
||||
{
|
||||
Path.Combine(AppContext.BaseDirectory, "Resources", $"{language}.json"),
|
||||
Path.Combine(Directory.GetCurrentDirectory(), "Resources", $"{language}.json"),
|
||||
};
|
||||
|
||||
searched.AddRange(paths);
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = await File.ReadAllTextAsync(path);
|
||||
var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
||||
if (dict != null && dict.Count > 0)
|
||||
{
|
||||
_translations = dict;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// try next path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_translations = new();
|
||||
}
|
||||
|
||||
private static string Fallback(string key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
"common.status.ready" => "Bereit",
|
||||
"common.cancel" => "Abbrechen",
|
||||
"common.error" => "Fehler:",
|
||||
"common.copy" => "Kopieren",
|
||||
"common.status.error" => "Fehler",
|
||||
"page.title.login" => "Anmelden - Author Buddy",
|
||||
"page.title.register" => "Registrieren - Author Buddy",
|
||||
"page.title.setup2fa" => "2FA einrichten - Author Buddy",
|
||||
"page.title.settings" => "Einstellungen",
|
||||
"page.title.editor" => "Editor - Author Buddy",
|
||||
"page.title.assistant" => "Assistent - Author Buddy",
|
||||
"page.title.models" => "Modelle - Author Buddy",
|
||||
"page.title.home" => "Dashboard - Author Buddy",
|
||||
"page.title.error" => "Fehler",
|
||||
"page.title.not_found" => "Seite nicht gefunden",
|
||||
"login.heading" => "Anmelden",
|
||||
"login.label.username" => "Benutzername",
|
||||
"login.label.password" => "Passwort",
|
||||
"login.button.submit" => "Anmelden",
|
||||
"login.link.register" => "Registrieren",
|
||||
"login.2fa.instruction" => "Gib deinen 2FA-Code ein:",
|
||||
"login.2fa.label.code" => "2FA-Code",
|
||||
"login.2fa.button.verify" => "Bestätigen",
|
||||
"login.error.empty_fields" => "Bitte Benutzername und Passwort eingeben.",
|
||||
"login.error.invalid_credentials" => "Ungültige Anmeldedaten.",
|
||||
"login.2fa.error.invalid_code" => "Der 2FA-Code muss 6-stellig sein.",
|
||||
"login.2fa.error.code_failed" => "Ungültiger 2FA-Code.",
|
||||
"nav.user.logged_in_as" => "Angemeldet als",
|
||||
"nav.user.manage_2fa" => "2FA verwalten",
|
||||
"nav.user.logout" => "Abmelden",
|
||||
_ => key,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -113,4 +113,52 @@ public class ProjectService : IProjectService
|
|||
{
|
||||
await _fileScannerService.ScanProjectFolderAsync(projectId, directoryPath, progress);
|
||||
}
|
||||
|
||||
public Task<int> CopyProjectAsync(int sourceProjectId, string newName, string newRootPath, int userId)
|
||||
{
|
||||
var col = _db.GetCollection<ProjectEntity>("projects");
|
||||
var source = col.FindById(sourceProjectId);
|
||||
if (source == null)
|
||||
throw new InvalidOperationException("Source project not found.");
|
||||
|
||||
Directory.CreateDirectory(newRootPath);
|
||||
CopyDirectory(source.RootPath, newRootPath);
|
||||
|
||||
var entity = new ProjectEntity
|
||||
{
|
||||
Name = newName,
|
||||
RootPath = newRootPath,
|
||||
LastOpened = DateTime.Now
|
||||
};
|
||||
col.Insert(entity);
|
||||
|
||||
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||
var projectSettings = settings.Find(s =>
|
||||
s.UserId == userId && s.ProjectId == sourceProjectId);
|
||||
foreach (var s in projectSettings)
|
||||
{
|
||||
settings.Insert(new SettingEntity
|
||||
{
|
||||
Key = s.Key,
|
||||
Value = s.Value,
|
||||
UserId = userId,
|
||||
ProjectId = entity.Id
|
||||
});
|
||||
}
|
||||
|
||||
return Task.FromResult(entity.Id);
|
||||
}
|
||||
|
||||
private static void CopyDirectory(string sourceDir, string destDir)
|
||||
{
|
||||
foreach (var dir in Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
Directory.CreateDirectory(dir.Replace(sourceDir, destDir));
|
||||
}
|
||||
foreach (var file in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
var dest = file.Replace(sourceDir, destDir);
|
||||
File.Copy(file, dest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class SettingsService : ISettingsService
|
|||
|
||||
private string? Get(string key)
|
||||
{
|
||||
return GetSetting(key, _currentUserId, null);
|
||||
return GetSetting(key, _currentUserId, _currentProjectId);
|
||||
}
|
||||
|
||||
private void Set(string key, string value)
|
||||
|
|
@ -221,31 +221,75 @@ public class SettingsService : ISettingsService
|
|||
public Task<UserEntity> GetCurrentUserAsync()
|
||||
{
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var user = col.FindOne(u => u.IsCurrent);
|
||||
return Task.FromResult(user ?? col.FindAll().First());
|
||||
if (_currentUserId != null)
|
||||
{
|
||||
var user = col.FindById(_currentUserId.Value);
|
||||
if (user != null) return Task.FromResult(user);
|
||||
}
|
||||
return Task.FromResult(col.FindAll().FirstOrDefault() ?? new UserEntity());
|
||||
}
|
||||
|
||||
public Task SetCurrentUserAsync(int userId)
|
||||
public void SetCurrentUser(int userId)
|
||||
{
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var users = col.FindAll().ToList();
|
||||
foreach (var u in users)
|
||||
{
|
||||
u.IsCurrent = u.Id == userId;
|
||||
col.Update(u);
|
||||
}
|
||||
_currentUserId = userId;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<UserEntity> CreateUserAsync(string name)
|
||||
{
|
||||
var col = _db.GetCollection<UserEntity>("users");
|
||||
var user = new UserEntity { Name = name };
|
||||
var hasUsers = col.FindAll().Any();
|
||||
var user = new UserEntity
|
||||
{
|
||||
Name = name,
|
||||
Role = hasUsers ? UserRole.Author : UserRole.Administrator
|
||||
};
|
||||
col.Insert(user);
|
||||
return Task.FromResult(user);
|
||||
}
|
||||
|
||||
private void MigrateSchema()
|
||||
{
|
||||
const string schemaKey = "_schema_version";
|
||||
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||
if (settings.FindOne(s => s.Key == schemaKey && s.UserId == null && s.ProjectId == null) != null)
|
||||
return;
|
||||
|
||||
var users = _db.GetCollection<UserEntity>("users");
|
||||
var all = users.FindAll().OrderBy(u => u.Id).ToList();
|
||||
if (all.Count > 0)
|
||||
{
|
||||
all[0].Role = UserRole.Administrator;
|
||||
foreach (var u in all)
|
||||
{
|
||||
u.IsActive = true;
|
||||
users.Update(u);
|
||||
}
|
||||
}
|
||||
|
||||
var authorExists = all.Any(u => u.Name == "Author");
|
||||
if (!authorExists)
|
||||
{
|
||||
var authorUser = new UserEntity
|
||||
{
|
||||
Name = "Author",
|
||||
PasswordHash = TotpHelper.HashPassword("author123"),
|
||||
TwoFactorEnabled = false,
|
||||
TwoFactorSecret = string.Empty,
|
||||
Role = UserRole.Author,
|
||||
IsActive = true
|
||||
};
|
||||
users.Insert(authorUser);
|
||||
}
|
||||
|
||||
settings.Insert(new SettingEntity
|
||||
{
|
||||
Key = schemaKey,
|
||||
Value = "1",
|
||||
UserId = null,
|
||||
ProjectId = null
|
||||
});
|
||||
}
|
||||
|
||||
public Task LoadProjectSettingsAsync()
|
||||
{
|
||||
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||
|
|
@ -274,19 +318,18 @@ public class SettingsService : ISettingsService
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task InitializeAsync(int projectId = -1)
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
var users = _db.GetCollection<UserEntity>("users");
|
||||
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||
MigrateSchema();
|
||||
|
||||
var userExists = users.FindAll().Any();
|
||||
if (userExists)
|
||||
if (_currentUserId == null)
|
||||
{
|
||||
var current = users.FindOne(u => u.IsCurrent);
|
||||
_currentUserId = current?.Id ?? users.FindAll().First().Id;
|
||||
var firstUser = _db.GetCollection<UserEntity>("users").FindAll().FirstOrDefault();
|
||||
if (firstUser == null) return Task.CompletedTask;
|
||||
_currentUserId = firstUser.Id;
|
||||
}
|
||||
|
||||
if (_currentUserId == null) return Task.CompletedTask;
|
||||
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||
|
||||
var lang = _ollamaConfig.Language;
|
||||
|
||||
|
|
@ -309,7 +352,7 @@ public class SettingsService : ISettingsService
|
|||
foreach (var entry in entries)
|
||||
{
|
||||
var existing = settings.FindOne(s =>
|
||||
s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == projectId);
|
||||
s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == _currentProjectId);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
|
|
@ -334,7 +377,7 @@ public class SettingsService : ISettingsService
|
|||
Key = entry.Key,
|
||||
Value = entry.Default,
|
||||
UserId = _currentUserId,
|
||||
ProjectId = null
|
||||
ProjectId = _currentProjectId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
using Microsoft.JSInterop;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace AuthorBuddy.Web.Services;
|
||||
|
||||
public class ThemeService : IThemeService
|
||||
{
|
||||
private readonly IJSRuntime _js;
|
||||
private string _theme = "";
|
||||
|
||||
public ThemeService(IJSRuntime js)
|
||||
{
|
||||
_js = js;
|
||||
}
|
||||
|
||||
public string Theme { get => _theme; }
|
||||
|
||||
public async Task ApplyTheme(string theme)
|
||||
{
|
||||
_theme = theme;
|
||||
await _js.InvokeVoidAsync("eval",
|
||||
$"document.getElementById('theme-css')?.remove(); " +
|
||||
$"var link = document.createElement('link'); " +
|
||||
|
|
|
|||
318
wwwroot/app.css
318
wwwroot/app.css
|
|
@ -95,10 +95,51 @@ body {
|
|||
}
|
||||
|
||||
.nav-item-sub {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.nav-item-text {
|
||||
flex: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: inherit;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-item-text:hover {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Settings context badge */
|
||||
.settings-context {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.settings-badge {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.settings-badge-project {
|
||||
background: var(--accent-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.settings-badge-user {
|
||||
background: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* Status bar */
|
||||
.status-bar {
|
||||
background: var(--status-bar-bg);
|
||||
|
|
@ -835,3 +876,280 @@ button.primary {
|
|||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Auth pages - logo above card */
|
||||
.auth-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.auth-logo img {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Sidebar logo */
|
||||
.sidebar-logo {
|
||||
text-align: center;
|
||||
padding: 12px 8px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.sidebar-logo img {
|
||||
max-width: 100px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Splash screen */
|
||||
.splash-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
background: var(--window-bg);
|
||||
}
|
||||
|
||||
.splash-bg {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0.15;
|
||||
}
|
||||
|
||||
.splash-content {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.splash-logo img {
|
||||
max-width: 200px;
|
||||
height: auto;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.splash-loader {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 4px solid var(--border-color);
|
||||
border-top-color: var(--accent-color);
|
||||
border-radius: 50%;
|
||||
animation: splash-spin 0.8s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes splash-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Info overlay content */
|
||||
.info-content {
|
||||
background: var(--card-bg);
|
||||
padding: 40px;
|
||||
border: 2px solid var(--border-color);
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.info-content h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 12px;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.info-version,
|
||||
.info-copyright {
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.info-homepage {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.info-homepage a {
|
||||
color: var(--accent-color);
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-homepage a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info-close-btn {
|
||||
margin-top: 16px;
|
||||
padding: 8px 24px;
|
||||
}
|
||||
|
||||
/* Sidebar info button */
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar-info-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--menu-bg);
|
||||
color: var(--text-color);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 8px auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-info-btn:hover {
|
||||
background: var(--accent-color);
|
||||
color: white;
|
||||
border-color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Editor modified badge */
|
||||
.editor-modified-badge {
|
||||
color: #e74c3c;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* Diff action buttons */
|
||||
.diff-actions {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Version list */
|
||||
.version-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.version-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.version-item.active {
|
||||
border-color: var(--accent-color);
|
||||
background: color-mix(in srgb, var(--accent-color) 10%, transparent);
|
||||
}
|
||||
|
||||
.version-item-info {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.version-date {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.version-comment {
|
||||
color: var(--border-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.version-item-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #c0392b;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 4px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #e74c3c;
|
||||
}
|
||||
|
||||
/* User management page */
|
||||
.usermanagement-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.usermanagement-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.usermanagement-table th,
|
||||
.usermanagement-table td {
|
||||
text-align: left;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.usermanagement-table th {
|
||||
font-weight: bold;
|
||||
background: var(--menu-bg);
|
||||
}
|
||||
|
||||
.usermanagement-current {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.usermanagement-inactive {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.usermanagement-status-active {
|
||||
color: #27ae60;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.usermanagement-status-inactive {
|
||||
color: #e74c3c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.usermanagement-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.usermanagement-status {
|
||||
margin-top: 12px;
|
||||
padding: 8px;
|
||||
border-radius: 3px;
|
||||
background: color-mix(in srgb, var(--accent-color) 15%, transparent);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue