mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-06-12 17:34:31 +02:00
feat: presets
This commit is contained in:
@@ -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 ImportProfile(models.Model):
|
||||||
class Versions(models.IntegerChoices):
|
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"))
|
yaml_config = models.TextField(verbose_name=_("YAML Configuration"))
|
||||||
version = models.IntegerField(
|
version = models.IntegerField(
|
||||||
choices=Versions,
|
choices=Versions,
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
from apps.import_app.services.v1 import ImportService as ImportServiceV1
|
from apps.import_app.services.v1 import ImportService as ImportServiceV1
|
||||||
|
|
||||||
|
from apps.import_app.services.presets import PresetService
|
||||||
|
|||||||
@@ -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 = [
|
urlpatterns = [
|
||||||
path("import/", views.import_view, name="import"),
|
path("import/", views.import_view, name="import"),
|
||||||
|
path(
|
||||||
|
"import/presets/",
|
||||||
|
views.import_presets_list,
|
||||||
|
name="import_presets_list",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"import/profiles/",
|
"import/profiles/",
|
||||||
views.import_profile_index,
|
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.forms import ImportRunFileUploadForm, ImportProfileForm
|
||||||
from apps.import_app.models import ImportRun, ImportProfile
|
from apps.import_app.models import ImportRun, ImportProfile
|
||||||
from apps.import_app.tasks import process_import
|
from apps.import_app.tasks import process_import
|
||||||
|
from apps.import_app.services import PresetService
|
||||||
|
|
||||||
|
|
||||||
def import_view(request):
|
def import_view(request):
|
||||||
@@ -28,6 +29,18 @@ def import_view(request):
|
|||||||
return HttpResponse("Hello, world. You're at the polls page.")
|
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
|
@login_required
|
||||||
@require_http_methods(["GET", "POST"])
|
@require_http_methods(["GET", "POST"])
|
||||||
def import_profile_index(request):
|
def import_profile_index(request):
|
||||||
@@ -54,6 +67,8 @@ def import_profile_list(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET", "POST"])
|
@require_http_methods(["GET", "POST"])
|
||||||
def import_profile_add(request):
|
def import_profile_add(request):
|
||||||
|
message = request.GET.get("message", None) or request.POST.get("message", None)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ImportProfileForm(request.POST)
|
form = ImportProfileForm(request.POST)
|
||||||
|
|
||||||
@@ -68,12 +83,19 @@ def import_profile_add(request):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
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(
|
return render(
|
||||||
request,
|
request,
|
||||||
"import_app/fragments/profiles/add.html",
|
"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' %}
|
{% extends 'extends/offcanvas.html' %}
|
||||||
|
{% load json %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block title %}{% translate 'Add new import profile' %}{% endblock %}
|
{% block title %}{% translate 'Add new import profile' %}{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% 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 %}
|
{% crispy form %}
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,13 +3,24 @@
|
|||||||
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
|
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
|
||||||
{% spaceless %}
|
{% spaceless %}
|
||||||
<div>{% translate 'Import Profiles' %}<span>
|
<div>{% translate 'Import Profiles' %}<span>
|
||||||
<a class="text-decoration-none tw-text-2xl p-1 category-action"
|
<span class="dropdown" data-bs-toggle="tooltip"
|
||||||
role="button"
|
data-bs-title="{% translate "Add" %}">
|
||||||
data-bs-toggle="tooltip"
|
<a class="text-decoration-none tw-text-2xl p-1" role="button"
|
||||||
data-bs-title="{% translate "Add" %}"
|
data-bs-toggle="dropdown"
|
||||||
hx-get="{% url 'import_profiles_add' %}"
|
data-bs-title="{% translate "Add" %}" aria-expanded="false">
|
||||||
hx-target="#generic-offcanvas">
|
<i class="fa-solid fa-circle-plus fa-fw"></i>
|
||||||
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
|
</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>
|
</span></div>
|
||||||
{% endspaceless %}
|
{% endspaceless %}
|
||||||
</div>
|
</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 %}
|
||||||
@@ -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