summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-08-28 02:56:35 +1000
committerJake Mannens <jake@asger.xyz>2023-08-28 02:56:35 +1000
commitff1b492c53b44fa10e7cd4170b4cfb0b7bfdc6e9 (patch)
tree0cca8e20b27bad74666772475ddbbab955b704c3
parent5128d5b72e89179d6a1e38c1b558e6a7309f7b4b (diff)
Added tag aliases and imrpoved selection dialog
-rw-r--r--Migrations/20230827144711_TagAlias.Designer.cs258
-rw-r--r--Migrations/20230827144711_TagAlias.cs42
-rw-r--r--Migrations/HBContextModelSnapshot.cs6
-rw-r--r--Pages/Component/TagSelectDialog.razor71
-rw-r--r--Pages/TagDefinitions.razor12
-rw-r--r--Services/TagService.cs18
-rw-r--r--Tag.cs1
7 files changed, 394 insertions, 14 deletions
diff --git a/Migrations/20230827144711_TagAlias.Designer.cs b/Migrations/20230827144711_TagAlias.Designer.cs
new file mode 100644
index 0000000..74efb10
--- /dev/null
+++ b/Migrations/20230827144711_TagAlias.Designer.cs
@@ -0,0 +1,258 @@
+// <auto-generated />
+using System;
+using HyperBooru;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace HyperBooru.Migrations
+{
+ [DbContext(typeof(HBContext))]
+ [Migration("20230827144711_TagAlias")]
+ partial class TagAlias
+ {
+ /// <inheritdoc />
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("HyperBooru.HBObject", b =>
+ {
+ b.Property<int>("ObjectId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ObjectId"));
+
+ b.Property<Guid>("Guid")
+ .HasColumnType("uuid");
+
+ b.HasKey("ObjectId");
+
+ b.HasIndex("Guid");
+
+ b.ToTable("Objects", (string)null);
+
+ b.UseTptMappingStrategy();
+ });
+
+ modelBuilder.Entity("HyperBooru.UploadedFile", b =>
+ {
+ b.Property<int>("UploadedFileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("UploadedFileId"));
+
+ b.Property<DateTime?>("CreateTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<string>("Filename")
+ .HasColumnType("text");
+
+ b.Property<DateTime?>("LastAccessTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<DateTime?>("LastWriteTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<int>("MediaObjectId")
+ .HasColumnType("integer");
+
+ b.Property<string>("OriginalChecksum")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property<DateTime>("UploadTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("UploadedFileId");
+
+ b.HasIndex("MediaObjectId");
+
+ b.ToTable("UploadedFiles", (string)null);
+ });
+
+ modelBuilder.Entity("TagDefinitionTagDefinition", b =>
+ {
+ b.Property<int>("ImplicitTagsObjectId")
+ .HasColumnType("integer");
+
+ b.Property<int>("TagDefinitionObjectId")
+ .HasColumnType("integer");
+
+ b.HasKey("ImplicitTagsObjectId", "TagDefinitionObjectId");
+
+ b.HasIndex("TagDefinitionObjectId");
+
+ b.ToTable("TagDefinitionTagDefinition");
+ });
+
+ modelBuilder.Entity("HyperBooru.Media", b =>
+ {
+ b.HasBaseType("HyperBooru.HBObject");
+
+ b.Property<string>("Checksum")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property<string>("LongDescription")
+ .HasColumnType("text");
+
+ b.Property<string>("MimeType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property<string>("ShortDescription")
+ .HasColumnType("text");
+
+ b.ToTable("Media", (string)null);
+ });
+
+ modelBuilder.Entity("HyperBooru.Tag", b =>
+ {
+ b.HasBaseType("HyperBooru.HBObject");
+
+ b.Property<DateTime>("CreateTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<int>("TagDefinitionObjectId")
+ .HasColumnType("integer");
+
+ b.Property<int>("TargetObjectId")
+ .HasColumnType("integer");
+
+ b.HasIndex("TagDefinitionObjectId");
+
+ b.HasIndex("TargetObjectId");
+
+ b.ToTable("Tags", (string)null);
+ });
+
+ modelBuilder.Entity("HyperBooru.TagDefinition", b =>
+ {
+ b.HasBaseType("HyperBooru.HBObject");
+
+ b.Property<string>("Alias")
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property<string>("Namespace")
+ .HasColumnType("text");
+
+ b.Property<int>("Source")
+ .HasColumnType("integer");
+
+ b.ToTable("TagDefinitions", (string)null);
+
+ b.HasData(
+ new
+ {
+ ObjectId = -1,
+ Guid = new Guid("ebdad4f8-455a-4351-8017-1d4854d6fa38"),
+ Name = "nsfw",
+ Source = 0
+ },
+ new
+ {
+ ObjectId = -2,
+ Guid = new Guid("ea212801-5bcc-4c0e-814f-fb9d30db58bc"),
+ Name = "ingest",
+ Source = 0
+ });
+ });
+
+ modelBuilder.Entity("HyperBooru.UploadedFile", b =>
+ {
+ b.HasOne("HyperBooru.Media", "Media")
+ .WithMany("UploadedFiles")
+ .HasForeignKey("MediaObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Media");
+ });
+
+ modelBuilder.Entity("TagDefinitionTagDefinition", b =>
+ {
+ b.HasOne("HyperBooru.TagDefinition", null)
+ .WithMany()
+ .HasForeignKey("ImplicitTagsObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("HyperBooru.TagDefinition", null)
+ .WithMany()
+ .HasForeignKey("TagDefinitionObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("HyperBooru.Media", b =>
+ {
+ b.HasOne("HyperBooru.HBObject", null)
+ .WithOne()
+ .HasForeignKey("HyperBooru.Media", "ObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("HyperBooru.Tag", b =>
+ {
+ b.HasOne("HyperBooru.HBObject", null)
+ .WithOne()
+ .HasForeignKey("HyperBooru.Tag", "ObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("HyperBooru.TagDefinition", "TagDefinition")
+ .WithMany()
+ .HasForeignKey("TagDefinitionObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("HyperBooru.HBObject", "Target")
+ .WithMany("Tags")
+ .HasForeignKey("TargetObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("TagDefinition");
+
+ b.Navigation("Target");
+ });
+
+ modelBuilder.Entity("HyperBooru.TagDefinition", b =>
+ {
+ b.HasOne("HyperBooru.HBObject", null)
+ .WithOne()
+ .HasForeignKey("HyperBooru.TagDefinition", "ObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("HyperBooru.HBObject", b =>
+ {
+ b.Navigation("Tags");
+ });
+
+ modelBuilder.Entity("HyperBooru.Media", b =>
+ {
+ b.Navigation("UploadedFiles");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Migrations/20230827144711_TagAlias.cs b/Migrations/20230827144711_TagAlias.cs
new file mode 100644
index 0000000..2ae9ede
--- /dev/null
+++ b/Migrations/20230827144711_TagAlias.cs
@@ -0,0 +1,42 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace HyperBooru.Migrations
+{
+ /// <inheritdoc />
+ public partial class TagAlias : Migration
+ {
+ /// <inheritdoc />
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn<string>(
+ name: "Alias",
+ table: "TagDefinitions",
+ type: "text",
+ nullable: true);
+
+ migrationBuilder.UpdateData(
+ table: "TagDefinitions",
+ keyColumn: "ObjectId",
+ keyValue: -2,
+ column: "Alias",
+ value: null);
+
+ migrationBuilder.UpdateData(
+ table: "TagDefinitions",
+ keyColumn: "ObjectId",
+ keyValue: -1,
+ column: "Alias",
+ value: null);
+ }
+
+ /// <inheritdoc />
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Alias",
+ table: "TagDefinitions");
+ }
+ }
+}
diff --git a/Migrations/HBContextModelSnapshot.cs b/Migrations/HBContextModelSnapshot.cs
index e535376..f0e4b1f 100644
--- a/Migrations/HBContextModelSnapshot.cs
+++ b/Migrations/HBContextModelSnapshot.cs
@@ -18,9 +18,6 @@ namespace HyperBooru.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.10")
- .HasAnnotation("Proxies:ChangeTracking", false)
- .HasAnnotation("Proxies:CheckEquality", false)
- .HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -142,6 +139,9 @@ namespace HyperBooru.Migrations
{
b.HasBaseType("HyperBooru.HBObject");
+ b.Property<string>("Alias")
+ .HasColumnType("text");
+
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
diff --git a/Pages/Component/TagSelectDialog.razor b/Pages/Component/TagSelectDialog.razor
index 5ab7b0a..f21d570 100644
--- a/Pages/Component/TagSelectDialog.razor
+++ b/Pages/Component/TagSelectDialog.razor
@@ -6,9 +6,11 @@
<link rel="stylesheet" href="@(nameof(HyperBooru)).styles.css"/>
<Dialog Title=@(Title ?? "Select one or more tag(s)") @ref=dialog>
- <input type="text" placeholder="Search"/>
+ <input type="text" placeholder="Search" @ref=queryInput @oninput=QueryInput @onkeypress=QueryKey value=@query autofocus/>
<div class="tag-definitions">
@for(int i = 0; i < tagDefinitions.Count(); i++) {
+ if(!MatchesQuery(tagDefinitions[i].tagDefinition))
+ continue;
var local = i;
<input
type="checkbox"
@@ -40,6 +42,7 @@
set {
if(value)
LoadTags();
+ query = null;
visible = dialog.Visible = value;
}
}
@@ -52,6 +55,9 @@
private bool visible;
+ private string? query;
+ private ElementReference queryInput;
+
public void Show() => Visible = true;
public void Hide() => Visible = false;
@@ -60,6 +66,11 @@
LoadTags();
}
+ protected override void OnAfterRender(bool firstRender) {
+ if(Visible)
+ queryInput.FocusAsync();
+ }
+
private void LoadTags() {
db = dbFactory.CreateDbContext();
@@ -79,6 +90,64 @@
.ToArray();
}
+ private void QueryInput(ChangeEventArgs e) {
+ query = (string?) e.Value;
+ StateHasChanged();
+ }
+
+ private void QueryKey(KeyboardEventArgs e) {
+ if(e.Code != "Enter" && e.Code != "NumpadEnter")
+ return;
+
+ if(string.IsNullOrEmpty(query)) {
+ Submit();
+ return;
+ }
+
+ int c = 0;
+ int? last = null;
+ for(int i = 0; i < tagDefinitions.Count(); i++) {
+ if(!MatchesQuery(tagDefinitions[i].tagDefinition))
+ continue;
+ last = i;
+ c++;
+ }
+
+ if(c == 1 && last is not null)
+ tagDefinitions[(int) last].selected =
+ !tagDefinitions[(int) last].selected;
+
+ query = null;
+ StateHasChanged();
+ }
+
+ private bool MatchesQuery(TagDefinition tagDef) {
+ TagDefinition? singleTag = null;
+
+ if(string.IsNullOrEmpty(query))
+ return true;
+
+ singleTag = tagDefinitions.FirstOrDefault(
+ e => string.Equals(
+ e.tagDefinition.Alias,
+ query,
+ StringComparison.OrdinalIgnoreCase)).tagDefinition;
+
+ if(singleTag is not null)
+ return tagDef.Guid == singleTag.Guid;
+
+ singleTag = tagDefinitions.FirstOrDefault(
+ e => string.Equals(
+ e.tagDefinition.Name,
+ query,
+ StringComparison.OrdinalIgnoreCase)).tagDefinition;
+
+ if(singleTag is not null)
+ return tagDef.Guid == singleTag.Guid;
+
+ return tagDef.Name.ToLower().Contains(query.ToLower());
+ }
+
private async void Submit() {
await OnSubmit.InvokeAsync(
tagDefinitions
diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor
index bd7394d..878b9a2 100644
--- a/Pages/TagDefinitions.razor
+++ b/Pages/TagDefinitions.razor
@@ -16,12 +16,14 @@
<TabPane Title="@(ns ?? "Default")">
<table id="tag-definitions" class="data-table">
<tr>
+ <th>Alias</th>
<th>Name</th>
<th>Implicit Tags</th>
<th></th>
</tr>
@foreach(var tagDef in tagDefinitions.Where(td => td.Namespace == ns)) {
<tr data-guid="@tagDef.Guid">
+ <td>@tagDef.Alias</td>
<td>@tagDef.Name</td>
<td>
<i>
@@ -59,6 +61,8 @@
<input type="text" @bind=tagName required/>
<label>Namespace</label>
<input type="text" @bind=tagNamespace/>
+ <label>Alias</label>
+ <input type="text" @bind=tagAlias/>
<div class="button-container">
<button class="secondary" @onclick=@(() => createTagDialog.Hide())>Cancel</button>
<button type="submit">Create</button>
@@ -72,6 +76,8 @@
<input type="text" @bind=tagName required/>
<label>Namespace</label>
<input type="text" @bind=tagNamespace/>
+ <label>Alias</label>
+ <input type="text" @bind=tagAlias/>
<div class="button-container">
<button class="secondary" @onclick=@(() => editTagDialog.Hide())>Cancel</button>
<button type="submit">Apply</button>
@@ -98,6 +104,7 @@
private string tagName;
private string? tagNamespace;
+ private string? tagAlias;
private TagDefinition? toDelete;
private TagDefinition? toEdit;
@@ -130,7 +137,7 @@
if(string.IsNullOrEmpty(tagNamespace))
tagNamespace = null;
- tagService.CreateTagDefinition(tagName, tagNamespace);
+ tagService.CreateTagDefinition(tagName, tagNamespace, tagAlias);
createTagDialog.Hide();
StateHasChanged();
}
@@ -139,6 +146,7 @@
this.toEdit = toEdit;
tagName = toEdit.Name;
tagNamespace = toEdit.Namespace;
+ tagAlias = toEdit.Alias;
editTagDialog.Show();
}
@@ -146,7 +154,7 @@
if(toEdit is null)
return;
- tagService.UpdateTagDefinition(toEdit, tagName, tagNamespace);
+ tagService.UpdateTagDefinition(toEdit, tagName, tagNamespace, tagAlias);
StateHasChanged();
}
diff --git a/Services/TagService.cs b/Services/TagService.cs
index a0fd19e..2648bb3 100644
--- a/Services/TagService.cs
+++ b/Services/TagService.cs
@@ -18,11 +18,11 @@ public interface ITagService {
public void AddImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef);
public void RemoveImplicitTag(Guid tagDef, Guid implicitTagDef);
public void RemoveImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef);
- public void CreateTagDefinition(string name, string? @namespace);
+ public void CreateTagDefinition(string name, string? @namespace = null, string? alias = null);
public void DeleteTagDefinition(Guid tagDef);
public void DeleteTagDefinition(TagDefinition tagDef);
- public void UpdateTagDefinition(Guid tagDef, string name, string? @namespace);
- public void UpdateTagDefinition(TagDefinition tagDef, string name, string? @namespace);
+ public void UpdateTagDefinition(Guid tagDef, string name, string? @namespace = null, string? alias = null);
+ public void UpdateTagDefinition(TagDefinition tagDef, string name, string? @namespace = null, string? alias = null);
public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj);
public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(HBObject obj);
public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(TagDefinition tagDef);
@@ -123,13 +123,14 @@ public class TagService : ITagService {
public void RemoveImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef) =>
RemoveImplicitTag(tagDef, implicitTagDef);
- public void CreateTagDefinition(string name, string? @namespace) {
+ public void CreateTagDefinition(string name, string? @namespace = null, string? alias = null) {
using var db = dbFactory.CreateDbContext();
TagDefinition tagdef = new() {
Source = TagSource.UserTag,
Namespace = @namespace,
- Name = name
+ Name = name,
+ Alias = alias
};
if(!db.TagDefinitions.Contains(tagdef))
db.TagDefinitions.Add(tagdef);
@@ -156,7 +157,7 @@ public class TagService : ITagService {
public void DeleteTagDefinition(TagDefinition tagDef) =>
DeleteTagDefinition(tagDef.Guid);
- public void UpdateTagDefinition(Guid tagDef, string name, string? @namespace) {
+ public void UpdateTagDefinition(Guid tagDef, string name, string? @namespace = null, string? alias = null) {
using var db = dbFactory.CreateDbContext();
if(string.IsNullOrEmpty(@namespace))
@@ -165,12 +166,13 @@ public class TagService : ITagService {
var tag = db.TagDefinitions.First(td => td.Guid == tagDef);
tag.Name = name;
tag.Namespace = @namespace;
+ tag.Alias = alias;
db.SaveChanges();
}
- public void UpdateTagDefinition(TagDefinition tagDef, string name, string? @namespace) =>
- UpdateTagDefinition(tagDef.Guid, name, @namespace);
+ public void UpdateTagDefinition(TagDefinition tagDef, string name, string? @namespace = null, string? alias = null) =>
+ UpdateTagDefinition(tagDef.Guid, name, @namespace, alias);
private (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(IEnumerable<TagDefinition> tagDefs) {
using var db = dbFactory.CreateDbContext();
diff --git a/Tag.cs b/Tag.cs
index 70d70c9..81c5f67 100644
--- a/Tag.cs
+++ b/Tag.cs
@@ -13,6 +13,7 @@ public class TagDefinition : HBObject {
public TagSource Source { get; set; } = TagSource.Internal;
public string? Namespace { get; set; }
public string Name { get; set; }
+ public string? Alias { get; set;}
public virtual List<TagDefinition> ImplicitTags { get; set; } = new();
}