feat: manual entity creation

chore: clippy
This commit is contained in:
Per Stark
2025-10-15 21:00:17 +02:00
parent 2964f1a5a5
commit 35ff4e1464
14 changed files with 653 additions and 43 deletions

View File

@@ -5,8 +5,16 @@
{% block main %}
<div id="knowledge_pane" class="flex justify-center grow mt-2 sm:mt-4 gap-6">
<div class="container">
<div class="nb-panel p-3 mb-4 flex flex-col sm:flex-row justify-between items-start sm:items-center">
<h2 class="text-xl font-extrabold tracking-tight">Knowledge Entities</h2>
<div class="nb-panel p-3 mb-4 space-y-3 sm:space-y-0 sm:flex sm:flex-row sm:justify-between sm:items-center">
<div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
<h2 class="text-xl font-extrabold tracking-tight">Knowledge Entities</h2>
<button type="button" class="nb-btn nb-cta btn-sm"
hx-get="/knowledge-entity/new"
hx-target="#modal"
hx-swap="innerHTML">
New Entity
</button>
</div>
<form hx-get="/knowledge" hx-target="#knowledge_pane" hx-push-url="true" hx-swap="outerHTML"
class="flex items-center gap-2 mt-2 sm:mt-0">
<input type="hidden" name="page" value="1" />
@@ -43,4 +51,4 @@
{% include "knowledge/relationship_table.html" %}
</div>
</div>
{% endblock %}
{% endblock %}

View File

@@ -0,0 +1,74 @@
{% extends "modal_base.html" %}
{% block modal_class %}max-w-4xl w-full{% endblock %}
{% block form_attributes %}
hx-post="/knowledge-entity"
hx-target="#knowledge_pane"
hx-swap="outerHTML"
{% endblock %}
{% block modal_content %}
<h3 class="text-xl font-extrabold tracking-tight">Create Knowledge Entity</h3>
<div class="flex flex-col gap-3">
<label class="w-full">
<div class="text-xs uppercase tracking-wide opacity-70 mb-1">Name</div>
<input type="text" name="name" class="nb-input w-full" placeholder="Entity title" required>
</label>
<label class="w-full">
<div class="text-xs uppercase tracking-wide opacity-70 mb-1">Type</div>
<select name="entity_type" class="nb-select w-full">
{% for et in entity_types %}
<option value="{{ et }}">{{ et }}</option>
{% endfor %}
</select>
</label>
<label class="w-full">
<div class="text-xs uppercase tracking-wide opacity-70 mb-1">Description</div>
<textarea name="description" class="nb-input w-full h-32"
placeholder="Describe this entity so it can be found later"></textarea>
</label>
</div>
<div class="u-hairline pt-3 mt-4 space-y-3">
<div class="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div>
<div class="text-xs uppercase tracking-wide opacity-70">Relationships</div>
<p class="text-xs opacity-70 max-w-md">
Select existing entities to link. Suggestions will pre-select likely matches.
</p>
</div>
<div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<label class="flex items-center gap-2">
<span class="text-xs uppercase tracking-wide opacity-70">Type</span>
<input type="text" name="relationship_type" value="{{ relationship_list.relationship_type }}"
class="nb-input w-28" placeholder="relates_to">
</label>
<button type="button" class="nb-btn btn-sm nb-cta sm:ml-2" hx-post="/knowledge-entity/suggestions"
hx-target="#relationship-list" hx-swap="outerHTML" hx-include="#modal_form">
Suggest Relationships
</button>
</div>
</div>
{% if relationship_list.relationship_options|length == 0 %}
<div id="relationship-list" class="nb-card p-4 text-sm opacity-70">
You need at least one existing entity before creating relationships.
</div>
{% else %}
{% set relationship_options = relationship_list.relationship_options %}
{% set relationship_type = relationship_list.relationship_type %}
{% set suggestion_count = relationship_list.suggestion_count %}
{% include "knowledge/relationship_selector.html" %}
{% endif %}
</div>
{% endblock %}
{% block primary_actions %}
<button type="submit" class="nb-btn nb-cta">
Create Entity
</button>
{% endblock %}

View File

@@ -0,0 +1,39 @@
<div id="relationship-list" class="space-y-3">
{% if suggestion_count > 0 %}
<div class="text-xs opacity-70">
Applied {{ suggestion_count }} suggestion{% if suggestion_count != 1 %}s{% endif %}. Toggle any you don't need.
</div>
{% endif %}
{% if relationship_options|length == 0 %}
<div class="nb-card p-4 text-sm opacity-70">
No entities available to relate yet.
</div>
{% else %}
<div class="nb-card max-h-56 overflow-y-auto divide-y">
{% for option in relationship_options %}
<label class="flex items-start gap-3 p-3 hover:bg-base-200 transition-colors cursor-pointer">
<input type="checkbox" name="relationship_ids" value="{{ option.entity.id }}" class="nb-checkbox mt-1" {% if
option.is_selected %}checked{% endif %}>
<div class="flex-1 min-w-0">
<div class="flex flex-wrap items-center gap-2">
<span class="font-medium truncate">{{ option.entity.name }}</span>
<span class="badge badge-xs badge-outline">{{ option.entity.entity_type }}</span>
{% if option.is_suggested %}
<span class="badge badge-xs badge-primary uppercase tracking-wide">Suggested</span>
{% endif %}
</div>
{% if option.entity.description %}
<p class="text-xs opacity-70 mt-1 truncate">{{ option.entity.description }}</p>
{% endif %}
{% if option.is_suggested and option.score is not none %}
<div class="text-[0.65rem] opacity-60 mt-1">
Match score {{ option.score | round(2) }}
</div>
{% endif %}
</div>
</label>
{% endfor %}
</div>
{% endif %}
</div>