mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-03-18 15:34:01 +01:00
feat: presets
This commit is contained in:
11
app/apps/common/templatetags/json.py
Normal file
11
app/apps/common/templatetags/json.py
Normal 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)
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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,
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from apps.import_app.services.v1 import ImportService as ImportServiceV1
|
||||
|
||||
from apps.import_app.services.presets import PresetService
|
||||
|
||||
45
app/apps/import_app/services/presets.py
Normal file
45
app/apps/import_app/services/presets.py
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %}
|
||||
13
app/templates/import_app/fragments/runs/log.html
Normal file
13
app/templates/import_app/fragments/runs/log.html
Normal 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 %}
|
||||
Reference in New Issue
Block a user