diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-08-17 04:38:03 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2025-08-18 17:03:21 +1000 |
| commit | 5d462af49365e84e0dfd7ed5bd862efb6b325cd1 (patch) | |
| tree | bdb2fbd894916ad0cdb5ce64fa68fdab9d2d8130 | |
| parent | cfa09334407e962f57ba4aca7905265d22424c33 (diff) | |
Added UI to set implicit tags
| -rw-r--r-- | MainLayout.razor | 20 | ||||
| -rw-r--r-- | Pages/Component/MediaTagTable.razor | 43 | ||||
| -rw-r--r-- | Pages/Component/TagSelectDialog.razor | 25 | ||||
| -rw-r--r-- | Pages/Index.razor | 2 | ||||
| -rw-r--r-- | Pages/TagDefinitions.razor | 44 | ||||
| -rw-r--r-- | Server.csproj | 4 | ||||
| -rw-r--r-- | Services/TagService.cs | 26 |
7 files changed, 102 insertions, 62 deletions
diff --git a/MainLayout.razor b/MainLayout.razor index b34bf64..bd0675b 100644 --- a/MainLayout.razor +++ b/MainLayout.razor @@ -2,14 +2,12 @@ <link href="@(nameof(HyperBooru)).styles.css" rel="stylesheet" /> -<main> - <div id="navbar"> - <a href="/">Home</a> - <a href="/TagDefinitions">Tags</a> - <input type="text" placeholder="Search"/> - </div> - @* <div id="content" style="overflow-y:@(ViewBag.ContentScroll ? "auto" : "hidden");padding:@(ViewBag.ContentMargin ?? "0");"> *@ - <div id="content"> - @Body - </div> -</main> +<div id="navbar"> + <a href="/">Home</a> + <a href="/TagDefinitions">Tags</a> + <input type="text" placeholder="Search"/> +</div> +@* <div id="content" style="overflow-y:@(ViewBag.ContentScroll ? "auto" : "hidden");padding:@(ViewBag.ContentMargin ?? "0");"> *@ +<div id="content"> + @Body +</div> diff --git a/Pages/Component/MediaTagTable.razor b/Pages/Component/MediaTagTable.razor index d4a4283..278304d 100644 --- a/Pages/Component/MediaTagTable.razor +++ b/Pages/Component/MediaTagTable.razor @@ -9,25 +9,25 @@ <th>Tag Name</th> <th></th> </tr> - @foreach(var tagDef in tagDefs) { + @foreach(var e in tagDefs) { <tr> <td> - @if(implicitTags[tagDef.Guid]) { - <i>@tagDef.Namespace</i> + @if(e.isImplicit) { + <i>@e.tagDef.Namespace</i> } else { - @tagDef.Namespace + @e.tagDef.Namespace } </td> <td> - @if(implicitTags[tagDef.Guid]) { - <i>@tagDef.Name</i> + @if(e.isImplicit) { + <i>@e.tagDef.Name</i> } else { - @tagDef.Name + @e.tagDef.Name } </td> <td> - @if(!implicitTags[tagDef.Guid]) { - <a href="javascript:;" @onclick=@(() => Delete(tagDef))>Delete</a> + @if(!e.isImplicit) { + <a href="javascript:;" @onclick=@(() => Delete(e.tagDef))>Delete</a> } </td> </tr> @@ -38,8 +38,7 @@ [Parameter] public Media Media { get; set; } - private TagDefinition[] tagDefs; - private Dictionary<Guid, bool> implicitTags; + private (TagDefinition tagDef, bool isImplicit)[] tagDefs; protected override void OnInitialized() => LoadTagDefs(); @@ -57,22 +56,8 @@ using var db = dbFactory.CreateDbContext(); var media = db.Media.First(m => m.ObjectId == Media.ObjectId); - tagDefs = GetTagRecursive( - media.Tags - .Select(t => t.TagDefinition)) - .Where(td => td.Source == TagSource.UserTag) - .OrderBy(td => td.Namespace) - .ThenBy(td => td.Name) - .ToArray(); - - implicitTags = new(tagDefs - .Select(td => new KeyValuePair<Guid, bool>( - td.Guid, - !media.Tags.Select(t => t.TagDefinition.Guid).Contains(td.Guid)))); -} - - private IEnumerable<TagDefinition> GetTagRecursive(IEnumerable<TagDefinition> tagDefs) => - tagDefs - .Concat(tagDefs.SelectMany(td => GetTagRecursive(td.ImplicitTags))) - .DistinctBy(td => td.Guid); + tagDefs = tagService.GetAllTags(Media) + .Where(e => e.tagDefinition.Source == TagSource.UserTag) + .ToArray(); + } } diff --git a/Pages/Component/TagSelectDialog.razor b/Pages/Component/TagSelectDialog.razor index b8ff1d1..699ca3a 100644 --- a/Pages/Component/TagSelectDialog.razor +++ b/Pages/Component/TagSelectDialog.razor @@ -38,9 +38,16 @@ [Parameter] public EventCallback<TagDefinition[]> OnSubmit { get; set; } + public TagDefinition[] SelectedTags { get; set; } = + Array.Empty<TagDefinition>(); + public bool Visible { get => visible; - set => visible = dialog.Visible = value; + set { + if(value) + LoadTags(); + visible = dialog.Visible = value; + } } private (TagDefinition tagDefinition, bool selected)[] tagDefinitions; @@ -54,18 +61,28 @@ public void Show() => Visible = true; public void Hide() => Visible = false; - protected override void OnInitialized() { + protected override void OnInitialized() => LoadTags(); + + private void LoadTags() { db = dbFactory.CreateDbContext(); + + var selected = SelectedTags.Select(td => td.Guid); + tagDefinitions = db.TagDefinitions .Where(td => td.Source == TagSource.UserTag) .OrderBy(td => td.Name) - .Select(td => new Tuple<TagDefinition, bool>(td, false).ToValueTuple()) + .Select(td => new Tuple<TagDefinition, bool>( + td, + selected.Contains(td.Guid)).ToValueTuple()) .ToArray(); } private async void Submit() { await OnSubmit.InvokeAsync( - tagDefinitions.Select(e => e.tagDefinition).ToArray()); + tagDefinitions + .Where(e => e.selected) + .Select(e => e.tagDefinition) + .ToArray()); for(int i = 0; i < tagDefinitions.Count(); i++) tagDefinitions[i].selected = false; Hide(); diff --git a/Pages/Index.razor b/Pages/Index.razor index a69d69c..4719530 100644 --- a/Pages/Index.razor +++ b/Pages/Index.razor @@ -10,7 +10,7 @@ <input type="submit" /> </form> -@foreach(var media in db.Media) { +@foreach(var media in db.Media.OrderByDescending(m => m.ObjectId)) { <a href="/ViewMedia?m=@(media.Guid)"> <img src="/media/thumb/@(media.Guid)?h=200" /> </a> diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor index b28ef0c..75e93f9 100644 --- a/Pages/TagDefinitions.razor +++ b/Pages/TagDefinitions.razor @@ -8,23 +8,27 @@ <table id="tag-definitions" class="data-table"> <tr> - <th>Source</th> <th>Namespace</th> <th>Name</th> <th>Implicit Tags</th> <th></th> </tr> @foreach(var tagDef in tagDefinitions) { - TagSourceMap.TryGetValue(tagDef.Source, out var source); <tr data-guid="@tagDef.Guid"> - <td>@(source ?? tagDef.Source.ToString())</td> <td>@tagDef.Namespace</td> <td>@tagDef.Name</td> - <td></td> <td> - <a href="javascript:showDeleteDialog('@tagDef.Guid');" @onclick=@(() => PromptToDelete(tagDef))> + <i> + @(string.Join(", ", tagDef.ImplicitTags.Select(it => it.Name).Order())) + </i> + </td> + <td> + <a href="javascript:;" @onclick=@(() => PromptToDelete(tagDef))> Delete </a> + <a href="javascript:;" @onclick=@(() => PromptImplicitTags(tagDef))> + Implicit Tags + </a> </td> </tr> } @@ -54,18 +58,20 @@ </div> </Dialog> +<TagSelectDialog + OnSubmit=SetImplicitTags + @ref=implicitTagDialog /> + @code { - private readonly Dictionary<TagSource, string> TagSourceMap = new() { - { TagSource.UserTag, "User" } - }; - - private Dialog createTagDialog; - private Dialog deleteTagDialog; + private Dialog createTagDialog; + private Dialog deleteTagDialog; + private TagSelectDialog implicitTagDialog; private string tagName; private string? tagNamespace; private TagDefinition? toDelete; + private TagDefinition? toEditImplicit; private IEnumerable<TagDefinition> tagDefinitions => dbFactory.CreateDbContext().TagDefinitions @@ -94,4 +100,20 @@ tagService.DeleteTagDefinition(toDelete); deleteTagDialog.Hide(); } + + private void PromptImplicitTags(TagDefinition toEditImplicit) { + this.toEditImplicit = toEditImplicit; + implicitTagDialog.SelectedTags = + toEditImplicit.ImplicitTags.ToArray(); + implicitTagDialog.Show(); + } + + private void SetImplicitTags(TagDefinition[] tagDefs) { + if(toEditImplicit is null) + return; + + foreach(var tagDef in tagDefs) + tagService.AddImplicitTag(toEditImplicit, tagDef); + StateHasChanged(); + } } diff --git a/Server.csproj b/Server.csproj index 5eb5f1d..10953e6 100644 --- a/Server.csproj +++ b/Server.csproj @@ -32,8 +32,4 @@ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> </ItemGroup> - <ItemGroup> - <Folder Include="Data\" /> - </ItemGroup> - </Project> diff --git a/Services/TagService.cs b/Services/TagService.cs index e0d1072..da2bb2d 100644 --- a/Services/TagService.cs +++ b/Services/TagService.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace HyperBooru.Services; @@ -12,6 +13,8 @@ public interface ITagService { public void RemoveImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef); public void CreateTagDefinition(string name, string? @namespace); public void DeleteTagDefinition(TagDefinition tagDef); + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj); + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(HBObject obj); } public class TagService : ITagService { @@ -97,4 +100,23 @@ public class TagService : ITagService { transaction.Commit(); } -}
\ No newline at end of file + + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj) { + IEnumerable<TagDefinition> GetTagRecursive(IEnumerable<TagDefinition> tagDefs) => + tagDefs + .Concat(tagDefs.SelectMany(td => GetTagRecursive(td.ImplicitTags))) + .DistinctBy(td => td.Guid); + + using var db = dbFactory.CreateDbContext(); + var @object = db.Objects.First(o => o.Guid == obj); + + var guids = @object.Tags.Select(t => t.TagDefinition.Guid); + + return GetTagRecursive(@object.Tags.Select(t => t.TagDefinition)) + .Select(td => new ValueTuple<TagDefinition, bool>(td, !guids.Contains(td.Guid))) + .ToArray(); + } + + public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(HBObject obj) => + GetAllTags(obj.Guid); +} |
