feat: presets

This commit is contained in:
Herculino Trotta
2025-01-23 11:43:35 -03:00
parent 16fbead2f9
commit cabd03e7e6
12 changed files with 223 additions and 12 deletions

View File

@@ -0,0 +1,11 @@
import json
from django import template
register = template.Library()
@register.filter("json")
def convert_to_json(value):
return json.dumps(value)

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.1.5 on 2025-01-23 03:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('import_app', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='importprofile',
name='name',
field=models.CharField(max_length=100, unique=True, verbose_name='Name'),
),
migrations.AlterField(
model_name='importprofile',
name='yaml_config',
field=models.TextField(verbose_name='YAML Configuration'),
),
]

View File

@@ -9,9 +9,9 @@ from apps.import_app.schemas import version_1
class ImportProfile(models.Model):
class Versions(models.IntegerChoices):
VERSION_1 = 1, _("Version 1")
VERSION_1 = 1, _("Version") + " 1"
name = models.CharField(max_length=100, verbose_name=_("Name"))
name = models.CharField(max_length=100, verbose_name=_("Name"), unique=True)
yaml_config = models.TextField(verbose_name=_("YAML Configuration"))
version = models.IntegerField(
choices=Versions,

View File

@@ -1 +1,3 @@
from apps.import_app.services.v1 import ImportService as ImportServiceV1
from apps.import_app.services.presets import PresetService

View File

@@ -0,0 +1,45 @@
import json
from pathlib import Path
from apps.import_app.models import ImportProfile
class PresetService:
PRESET_PATH = "/usr/src/app/import_presets"
@classmethod
def get_all_presets(cls):
presets = []
for folder in Path(cls.PRESET_PATH).iterdir():
if folder.is_dir():
manifest_path = folder / "manifest.json"
config_path = folder / "config.yml"
if manifest_path.exists() and config_path.exists():
with open(manifest_path) as f:
manifest = json.load(f)
with open(config_path) as f:
config = json.dumps(f.read())
try:
preset = {
"name": manifest.get("name", folder.name),
"description": manifest.get("description", ""),
"message": json.dumps(manifest.get("message", "")),
"authors": manifest.get("author", "").split(","),
"schema_version": (int(manifest.get("schema_version", 1))),
"folder_name": folder.name,
"config": config,
}
ImportProfile.Versions(
preset["schema_version"]
) # Check if schema version is valid
except Exception as e:
print(e)
else:
presets.append(preset)
return presets

View File

@@ -3,6 +3,11 @@ import apps.import_app.views as views
urlpatterns = [
path("import/", views.import_view, name="import"),
path(
"import/presets/",
views.import_presets_list,
name="import_presets_list",
),
path(
"import/profiles/",
views.import_profile_index,

View File

@@ -13,6 +13,7 @@ from apps.common.decorators.htmx import only_htmx
from apps.import_app.forms import ImportRunFileUploadForm, ImportProfileForm
from apps.import_app.models import ImportRun, ImportProfile
from apps.import_app.tasks import process_import
from apps.import_app.services import PresetService
def import_view(request):
@@ -28,6 +29,18 @@ def import_view(request):
return HttpResponse("Hello, world. You're at the polls page.")
@login_required
@require_http_methods(["GET"])
def import_presets_list(request):
presets = PresetService.get_all_presets()
print(presets)
return render(
request,
"import_app/fragments/profiles/list_presets.html",
{"presets": presets},
)
@login_required
@require_http_methods(["GET", "POST"])
def import_profile_index(request):
@@ -54,6 +67,8 @@ def import_profile_list(request):
@login_required
@require_http_methods(["GET", "POST"])
def import_profile_add(request):
message = request.GET.get("message", None) or request.POST.get("message", None)
if request.method == "POST":
form = ImportProfileForm(request.POST)
@@ -68,12 +83,19 @@ def import_profile_add(request):
},
)
else:
form = ImportProfileForm()
print(int(request.GET.get("version", 1)))
form = ImportProfileForm(
initial={
"name": request.GET.get("name"),
"version": int(request.GET.get("version", 1)),
"yaml_config": request.GET.get("yaml_config"),
}
)
return render(
request,
"import_app/fragments/profiles/add.html",
{"form": form},
{"form": form, "message": message},
)

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.1.5 on 2025-01-23 03:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0013_usersettings_date_format_and_more'),
]
operations = [
migrations.AlterField(
model_name='usersettings',
name='date_format',
field=models.CharField(default='SHORT_DATE_FORMAT', max_length=100, verbose_name='Date Format'),
),
migrations.AlterField(
model_name='usersettings',
name='datetime_format',
field=models.CharField(default='SHORT_DATETIME_FORMAT', max_length=100, verbose_name='Datetime Format'),
),
migrations.AlterField(
model_name='usersettings',
name='language',
field=models.CharField(choices=[('auto', 'Auto'), ('en', 'English'), ('nl', 'Nederlands'), ('pt-br', 'Português (Brasil)')], default='auto', max_length=10, verbose_name='Language'),
),
]

View File

@@ -1,11 +1,19 @@
{% extends 'extends/offcanvas.html' %}
{% load json %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Add new import profile' %}{% endblock %}
{% block body %}
<form hx-post="{% url 'import_profiles_add' %}" hx-target="#generic-offcanvas" novalidate>
{% if message %}
<div class="alert alert-info" role="alert" id="msg" hx-preserve="true">
<h6 class="alert-heading tw-italic tw-font-bold">{% trans 'A message from the author' %}</h6>
<hr>
<p class="mb-0">{{ message|linebreaksbr }}</p>
</div>
{% endif %}
<form hx-post="{% url 'import_profiles_add' %}" hx-target="#generic-offcanvas" novalidate hx-vals='{"message": {% if message %}{{ message|json }}{% else %}""{% endif %}}'>
{% crispy form %}
</form>
{% endblock %}

View File

@@ -3,13 +3,24 @@
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
{% spaceless %}
<div>{% translate 'Import Profiles' %}<span>
<a class="text-decoration-none tw-text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
hx-get="{% url 'import_profiles_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
<span class="dropdown" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}">
<a class="text-decoration-none tw-text-2xl p-1" role="button"
data-bs-toggle="dropdown"
data-bs-title="{% translate "Add" %}" aria-expanded="false">
<i class="fa-solid fa-circle-plus fa-fw"></i>
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item"
role="button"
hx-get="{% url 'import_profiles_add' %}"
hx-target="#generic-offcanvas">{% trans 'New' %}</a></li>
<li><a class="dropdown-item"
role="button"
hx-get="{% url 'import_presets_list' %}"
hx-target="#persistent-generic-offcanvas-left">{% trans 'From preset' %}</a></li>
</ul>
</span>
</span></div>
{% endspaceless %}
</div>

View File

@@ -0,0 +1,43 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Import Presets' %}{% endblock %}
{% block body %}
{% if presets %}
<div id="search" class="mb-3">
<label class="w-100">
<input type="search"
class="form-control"
placeholder="{% translate 'Search' %}"
_="on input or search
show < .col /> in <#items/>
when its textContent.toLowerCase() contains my value.toLowerCase()"/>
</label>
</div>
<div class="row row-cols-1 g-4" id="items">
{% for preset in presets %}
<a class="text-decoration-none"
role="button"
hx-get="{% url 'import_profiles_add' %}"
hx-vals='{"yaml_config": {{ preset.config }}, "name": "{{ preset.name }}", "version": "{{ preset.schema_version }}", "message": {{ preset.message }}}'
hx-target="#generic-offcanvas">
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ preset.name }}</h5>
<hr>
<p>{{ preset.description }}</p>
<p>{% trans 'By' %} {{ preset.authors|join:", " }}</p>
</div>
</div>
</div>
</a>
{% endfor %}
{% else %}
<c-msg.empty title="{% translate "No presets yet" %}"></c-msg.empty>
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Logs for' %} #{{ run.id }}{% endblock %}
{% block body %}
<div class="card tw-max-h-full tw-overflow-auto">
<div class="card-body">
{{ run.logs|linebreaks }}
</div>
</div>
{% endblock %}