diff --git a/.gitignore b/.gitignore index 7b6caf3..5ab3c7c 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ + +node_modules/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1c0cfda --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "djlint.showInstallError": false, + "files.associations": { + "*.css": "tailwindcss" + }, + "tailwindCSS.experimental.configFile": "frontend/src/styles/tailwind.css", +} \ No newline at end of file diff --git a/app/WYGIWYH/settings.py b/app/WYGIWYH/settings.py index cf5db80..12dd32c 100644 --- a/app/WYGIWYH/settings.py +++ b/app/WYGIWYH/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/ """ import os +import re import sys from pathlib import Path @@ -46,7 +47,7 @@ INSTALLED_APPS = [ "django.contrib.sites", "whitenoise.runserver_nostatic", "django.contrib.staticfiles", - "webpack_boilerplate", + "django_vite", "django.contrib.humanize", "django.contrib.postgres", "django_browser_reload", @@ -128,6 +129,14 @@ STORAGES = { WHITENOISE_MANIFEST_STRICT = False + +def immutable_file_test(path, url): + # Match vite (rollup)-generated hashes, à la, `some_file-CSliV9zW.js` + return re.match(r"^.+[.-][0-9a-zA-Z_-]{8,12}\..+$", url) + + +WHITENOISE_IMMUTABLE_FILE_TEST = immutable_file_test + WSGI_APPLICATION = "WYGIWYH.wsgi.application" @@ -289,7 +298,7 @@ STATIC_URL = "static/" STATIC_ROOT = BASE_DIR / "static_files" STATICFILES_DIRS = [ - ROOT_DIR / "frontend/build", + ROOT_DIR / "frontend" / "build", BASE_DIR / "static", ] @@ -305,9 +314,10 @@ CACHES = { } } -WEBPACK_LOADER = { - "MANIFEST_FILE": ROOT_DIR / "frontend/build/manifest.json", -} +DJANGO_VITE_ASSETS_PATH = ROOT_DIR / "frontend" / "build" +DJANGO_VITE_MANIFEST_PATH = DJANGO_VITE_ASSETS_PATH / "manifest.json" +DJANGO_VITE_DEV_MODE = DEBUG +DJANGO_VITE_DEV_SERVER_PORT = 5173 # Default primary key field type # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field @@ -354,8 +364,12 @@ ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter" SOCIALACCOUNT_ADAPTER = "allauth.socialaccount.adapter.DefaultSocialAccountAdapter" # CRISPY FORMS -CRISPY_ALLOWED_TEMPLATE_PACKS = ["bootstrap5", "crispy_forms/pure_text"] -CRISPY_TEMPLATE_PACK = "bootstrap5" +CRISPY_ALLOWED_TEMPLATE_PACKS = [ + "bootstrap5", + "crispy_forms/pure_text", + "crispy-daisyui", +] +CRISPY_TEMPLATE_PACK = "crispy-daisyui" SESSION_EXPIRE_AT_BROWSER_CLOSE = False SESSION_COOKIE_AGE = int(os.getenv("SESSION_EXPIRY_TIME", 2678400)) # 31 days diff --git a/app/templates/account_groups/fragments/list.html b/app/templates/account_groups/fragments/list.html index adc7a78..aae721a 100644 --- a/app/templates/account_groups/fragments/list.html +++ b/app/templates/account_groups/fragments/list.html @@ -1,9 +1,9 @@ {% load i18n %} -
-
+
+
{% spaceless %}
{% translate 'Account Groups' %} - -
-
+
+
{% if account_groups %} - +
- - + + {% for account_group in account_groups %} - - + {% endfor %} diff --git a/app/templates/accounts/fragments/account_reconciliation.html b/app/templates/accounts/fragments/account_reconciliation.html index 9189421..1cf5f2a 100644 --- a/app/templates/accounts/fragments/account_reconciliation.html +++ b/app/templates/accounts/fragments/account_reconciliation.html @@ -9,65 +9,60 @@ {% csrf_token %} {{ form.management_form }} -
+
{% for form in form.forms %} -
-

- -

-
-
-
-
- {% translate 'Current balance' %} -
-
- {% currency_display amount=form.current_balance prefix=form.currency_prefix suffix=form.currency_suffix decimal_places=form.currency_decimal_places %} -
+
+ + +
+
+
+ {% translate 'Current balance' %}
-
- {% crispy form %} +
+ {% currency_display amount=form.current_balance prefix=form.currency_prefix suffix=form.currency_suffix decimal_places=form.currency_decimal_places %}
-
-
- {% translate 'Difference' %} -
-
-
+
+
+ {% crispy form %} +
+
+
+ {% translate 'Difference' %}
+
-
{% endfor %}
-
+
- +
diff --git a/app/templates/accounts/fragments/list.html b/app/templates/accounts/fragments/list.html index f5ef5ed..a6b2c6c 100644 --- a/app/templates/accounts/fragments/list.html +++ b/app/templates/accounts/fragments/list.html @@ -1,9 +1,9 @@ {% load i18n %} -
-
+
+
{% spaceless %}
{% translate 'Accounts' %} - -
-
+
+
{% if accounts %} -
{% translate 'Name' %}{% translate 'Name' %}
+
- - - - - - - + + + + + + + {% for account in accounts %} - - - - - - - + + + + + + {% endfor %} diff --git a/app/templates/calendar_view/fragments/list.html b/app/templates/calendar_view/fragments/list.html index 18f6c24..c579beb 100644 --- a/app/templates/calendar_view/fragments/list.html +++ b/app/templates/calendar_view/fragments/list.html @@ -2,40 +2,40 @@ {% load i18n %}
-
-
+
+
{% translate 'MON' %}
-
+
{% translate 'TUE' %}
-
+
{% translate 'WED' %}
-
+
{% translate 'THU' %}
-
+
{% translate 'FRI' %}
-
+
{% translate 'SAT' %}
-
+
{% translate 'SUN' %}
{% for date in dates %} {% if date %} -
-
-
{{ date.date|date:"l"|lower }}
-
{{ date.day }}
+
+
{{ date.date|date:"l"|lower }}
+
{{ date.day }}
-
+
{% for transaction in date.transactions %} {% if transaction.is_paid %} {% if transaction.type == "IN" and not transaction.account.is_asset %} @@ -62,7 +62,7 @@
{% else %} -
+
{% endif %} {% endfor %}
diff --git a/app/templates/calendar_view/pages/calendar.html b/app/templates/calendar_view/pages/calendar.html index acc63da..83b95c5 100644 --- a/app/templates/calendar_view/pages/calendar.html +++ b/app/templates/calendar_view/pages/calendar.html @@ -3,7 +3,6 @@ {% load i18n %} {% load month_name %} {% load static %} -{% load webpack_loader %} {% block title %}{% translate 'Monthly Overview' %} :: {{ month|month_name }}/{{ year }}{% endblock %} @@ -13,28 +12,28 @@ {% endblock %} {% block content %} -
{% translate 'Name' %}{% translate 'Group' %}{% translate 'Currency' %}{% translate 'Exchange Currency' %}{% translate 'Is Asset' %}{% translate 'Archived' %}{% translate 'Name' %}{% translate 'Group' %}{% translate 'Currency' %}{% translate 'Exchange Currency' %}{% translate 'Is Asset' %}{% translate 'Archived' %}
+
- - - + + + {% for category in categories %} - - - + {% endfor %} diff --git a/app/templates/common/fragments/month_year_picker.html b/app/templates/common/fragments/month_year_picker.html index 8ed07d7..3fddec8 100644 --- a/app/templates/common/fragments/month_year_picker.html +++ b/app/templates/common/fragments/month_year_picker.html @@ -7,49 +7,33 @@ {% block body %} {% regroup month_year_data by year as years_list %} - -
- {% for x in years_list %} - -
-
- {% trans 'Today' %} +
+ {% endblock %} diff --git a/app/templates/common/fragments/toasts.html b/app/templates/common/fragments/toasts.html index 84727bc..f917338 100644 --- a/app/templates/common/fragments/toasts.html +++ b/app/templates/common/fragments/toasts.html @@ -2,19 +2,25 @@ {% load toast_bg %} {% if messages %} {% for message in messages %} -
+ {% if formset.readonly and not formset.queryset.exists %} + {% else %} + + {% for field in formset.forms.0 %} + {% if field.label and not field.is_hidden %} + + {% endif %} + {% endfor %} + + {% endif %} + + + + + {% for field in formset.empty_form %} + {% include 'crispy-daisyui/field.html' with tag="td" form_show_labels=False %} + {% endfor %} + + + {% for form in formset %} + {% if form_show_errors and not form.is_extra %} + {% include "crispy-daisyui/errors.html" %} + {% endif %} + + + {% for field in form %} + {% include 'crispy-daisyui/field.html' with tag="td" form_show_labels=False %} + {% endfor %} + + {% endfor %} + +
{% translate 'Name' %}{% translate 'Muted' %}{% translate 'Name' %}{% translate 'Muted' %}
-
- +
+ - {% if not category.owner %} - {% endif %} {% if user == category.owner %} -
{{ category.name }} - {% if category.mute %}{% endif %} + {{ category.name }} + {% if category.mute %}{% endif %}
+ {{ field.label }}{% if field.field.required and not field|is_checkbox %}*{% endif %} +
+ + {% include "crispy-daisyui/inputs.html" %} + +{% if formset_tag %}{% endif %} +{% endspecialspaceless %} diff --git a/app/templates/crispy-daisyui/uni_form.html b/app/templates/crispy-daisyui/uni_form.html new file mode 100644 index 0000000..c585588 --- /dev/null +++ b/app/templates/crispy-daisyui/uni_form.html @@ -0,0 +1,11 @@ +{% load crispy_forms_utils %} + +{% specialspaceless %} + {% if include_media %}{{ form.media }}{% endif %} + {% if form_show_errors %} + {% include "crispy-daisyui/errors.html" %} + {% endif %} + {% for field in form %} + {% include field_template %} + {% endfor %} +{% endspecialspaceless %} diff --git a/app/templates/crispy-daisyui/uni_formset.html b/app/templates/crispy-daisyui/uni_formset.html new file mode 100644 index 0000000..4030be6 --- /dev/null +++ b/app/templates/crispy-daisyui/uni_formset.html @@ -0,0 +1,8 @@ +{% with formset.management_form as form %} + {% include 'crispy-daisyui/uni_form.html' %} +{% endwith %} +{% for form in formset %} +
+ {% include 'crispy-daisyui/uni_form.html' %} +
+{% endfor %} diff --git a/app/templates/crispy-daisyui/whole_uni_form.html b/app/templates/crispy-daisyui/whole_uni_form.html new file mode 100644 index 0000000..f986797 --- /dev/null +++ b/app/templates/crispy-daisyui/whole_uni_form.html @@ -0,0 +1,14 @@ +{% load crispy_forms_utils %} + +{% specialspaceless %} +{% if form_tag %}
{% endif %} + {% if form_method|lower == 'post' and not disable_csrf %} + {% csrf_token %} + {% endif %} + + {% include "crispy-daisyui/display_form.html" %} + + {% include "crispy-daisyui/inputs.html" %} + +{% if form_tag %}
{% endif %} +{% endspecialspaceless %} diff --git a/app/templates/crispy-daisyui/whole_uni_formset.html b/app/templates/crispy-daisyui/whole_uni_formset.html new file mode 100644 index 0000000..1070a88 --- /dev/null +++ b/app/templates/crispy-daisyui/whole_uni_formset.html @@ -0,0 +1,30 @@ +{% load crispy_forms_tags %} +{% load crispy_forms_utils %} + +{% specialspaceless %} +{% if formset_tag %} +
+{% endif %} + {% if formset_method|lower == 'post' and not disable_csrf %} + {% csrf_token %} + {% endif %} + +
+ {{ formset.management_form|crispy }} +
+ + {% include "crispy-daisyui/errors_formset.html" %} + + {% for form in formset %} + {% include "crispy-daisyui/display_form.html" %} + {% endfor %} + + {% if inputs %} +
+ {% for input in inputs %} + {% include "crispy-daisyui/layout/baseinput.html" %} + {% endfor %} +
+ {% endif %} +{% if formset_tag %}
{% endif %} +{% endspecialspaceless %} diff --git a/app/templates/currencies/fragments/list.html b/app/templates/currencies/fragments/list.html index db4d6b2..7648696 100644 --- a/app/templates/currencies/fragments/list.html +++ b/app/templates/currencies/fragments/list.html @@ -1,9 +1,9 @@ {% load i18n %} -
-
+
+
{% spaceless %}
{% translate 'Currencies' %} - -
-
+
+
{% if currencies %} - +
- - - - + + + + {% for currency in currencies %} - - - - + + + {% endfor %} diff --git a/app/templates/dca/fragments/strategy/details.html b/app/templates/dca/fragments/strategy/details.html index 10d9563..e4e6f15 100644 --- a/app/templates/dca/fragments/strategy/details.html +++ b/app/templates/dca/fragments/strategy/details.html @@ -1,13 +1,13 @@ {% load currency_display %} {% load i18n %} -
-
-
+
+
+
{{ strategy.name }}
-
-
- {{ strategy.payment_currency.name }} x {{ strategy.target_currency.name }} +
+
+ {{ strategy.payment_currency.name }} x {{ strategy.target_currency.name }}
{% if strategy.current_price %} @@ -25,13 +25,13 @@
-
-
-
-
+
+
+
+
{% spaceless %} -
{% trans "Entries" %} - {% trans "Entries" %} + -
{% translate 'Code' %}{% translate 'Name' %}{% translate 'Archived' %}{% translate 'Code' %}{% translate 'Name' %}{% translate 'Archived' %}
- {{ currency.code }}{{ currency.name }}{% if currency.is_archived %}{% endif %}{{ currency.code }}{{ currency.name }}{% if currency.is_archived %}{% endif %}
+
+
@@ -59,9 +59,9 @@ {% for entry in entries %} - @@ -127,13 +127,13 @@ -
-
-
-
-
-
{% trans "Total Invested" %}
-
+
+
+
+
+
+
{% trans "Total Invested" %}
+
-
-
-
-
{% trans "Total Received" %}
-
+
+
+
+
{% trans "Total Received" %}
+
-
-
-
-
{% trans "Current Total Value" %}
-
+
+
+
+
{% trans "Current Total Value" %}
+
-
-
-
-
{% trans "Average Entry Price" %}
-
+
+
+
+
{% trans "Average Entry Price" %}
+
-
-
-
-
{% trans "Total P/L" %}
+
+
+
+
{% trans "Total P/L" %}
+ class="tw:text-base-content {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}">
-
-
-
-
{% trans "Total % P/L" %}
+
+
+
+
{% trans "Total % P/L" %}
+ class="tw:text-base-content {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}"> {{ strategy.total_profit_loss_percentage|floatformat:2 }}%
-
-
+
-
-
-
{% trans "Performance Over Time" %}
+
+
+
{% trans "Performance Over Time" %}
-
-
+
-
-
-
{% trans "Entry Price vs Current Price" %}
+
+
+
{% trans "Entry Price vs Current Price" %}
-
-
+
-
-
-
{% trans "Investment Frequency" %}
-

+

- {% if entry.profit_loss_percentage > 0 %} - {{ entry.profit_loss_percentage|floatformat:"2g" }}% + {{ entry.profit_loss_percentage|floatformat:"2g" }}% {% elif entry.profit_loss_percentage < 0 %} - {{ entry.profit_loss_percentage|floatformat:"2g" }}% + {{ entry.profit_loss_percentage|floatformat:"2g" }}% {% endif %}
+
- - + + {% for entity in entities %} - - + {% endfor %} diff --git a/app/templates/exchange_rates/fragments/list.html b/app/templates/exchange_rates/fragments/list.html index a3436ab..90090da 100644 --- a/app/templates/exchange_rates/fragments/list.html +++ b/app/templates/exchange_rates/fragments/list.html @@ -1,10 +1,10 @@ {% load currency_display %} {% load i18n %} -
{% translate 'Name' %}{% translate 'Name' %}
-
- +
+ - {% if not entity.owner %} - {% endif %} {% if user == entity.owner %} -
{{ entity.name }}{{ entity.name }}
+
+
- - - - + + + + {% for exchange_rate in page_obj %} - - - - + + + {% endfor %} @@ -52,13 +52,12 @@ {% endif %} {% if page_obj.has_other_pages %} - {% endif %} diff --git a/app/templates/exchange_rates_services/fragments/list.html b/app/templates/exchange_rates_services/fragments/list.html index 5737f35..290707c 100644 --- a/app/templates/exchange_rates_services/fragments/list.html +++ b/app/templates/exchange_rates_services/fragments/list.html @@ -1,10 +1,10 @@ {% load currency_display %} {% load i18n %} -
{% translate 'Date' %}{% translate 'Pairing' %}{% translate 'Rate' %}{% translate 'Date' %}{% translate 'Pairing' %}{% translate 'Rate' %}
- {{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}{{ exchange_rate.from_currency.name }} x {{ exchange_rate.to_currency.name }}1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}{{ exchange_rate.from_currency.name }} x {{ exchange_rate.to_currency.name }}1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}
+
+
- - - - - - + + + + + + {% for service in services %} - - - - - - + + + + + {% endfor %} diff --git a/app/templates/exchange_rates_services/fragments/table.html b/app/templates/exchange_rates_services/fragments/table.html index 33cb6a9..d7fc880 100644 --- a/app/templates/exchange_rates_services/fragments/table.html +++ b/app/templates/exchange_rates_services/fragments/table.html @@ -1,23 +1,23 @@ {% load currency_display %} {% load i18n %} -
+
{% if page_obj %} -
-
{% translate 'Name' %}{% translate 'Service' %}{% translate 'Targeting' %}{% translate 'Last fetch' %}{% translate 'Name' %}{% translate 'Service' %}{% translate 'Targeting' %}{% translate 'Last fetch' %}
- {% if service.is_active %}{% else %} - {% endif %}{{ service.name }}{{ service.get_service_type_display }}{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}{% if service.is_active %}{% else %} + {% endif %}{{ service.name }}{{ service.get_service_type_display }}{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}
+
+
- - - - + + + + {% for exchange_rate in page_obj %} - - - - + + + {% endfor %} @@ -52,13 +52,12 @@ {% endif %} {% if page_obj.has_other_pages %} -
+
{% endif %} diff --git a/app/templates/export_app/fragments/export.html b/app/templates/export_app/fragments/export.html index 8a41a9f..217fe0b 100644 --- a/app/templates/export_app/fragments/export.html +++ b/app/templates/export_app/fragments/export.html @@ -5,8 +5,8 @@ {% block title %}{% translate 'Export' %}{% endblock %} {% block body %} -
-
+
+ {% crispy form %}
diff --git a/app/templates/export_app/fragments/restore.html b/app/templates/export_app/fragments/restore.html index c158a75..8431906 100644 --- a/app/templates/export_app/fragments/restore.html +++ b/app/templates/export_app/fragments/restore.html @@ -5,12 +5,12 @@ {% block title %}{% translate 'Restore' %}{% endblock %} {% block body %} -
+
+ class="show-loading tw:px-1"> {% crispy form %}
diff --git a/app/templates/extends/offcanvas.html b/app/templates/extends/offcanvas.html index 6f5cef9..3d8f627 100644 --- a/app/templates/extends/offcanvas.html +++ b/app/templates/extends/offcanvas.html @@ -1,8 +1,7 @@ {% load i18n %} -{% load webpack_loader %} -
-
{% block title %}{% endblock %}
- +
+
{% block title %}{% endblock %}
+
-
+
+
{% spaceless %}
{% translate 'Import Profiles' %} - - - @@ -25,45 +23,45 @@ {% endspaceless %}
-
-
+
+
{% if profiles %} -
{% translate 'Date' %}{% translate 'Pairing' %}{% translate 'Rate' %}{% translate 'Date' %}{% translate 'Pairing' %}{% translate 'Rate' %}
- {{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}{{ exchange_rate.from_currency.name }} x {{ exchange_rate.to_currency.name }}1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}{{ exchange_rate.from_currency.name }} x {{ exchange_rate.to_currency.name }}1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}
+
- - - + + + {% for profile in profiles %} - - - + + {% endfor %} diff --git a/app/templates/import_app/fragments/profiles/list_presets.html b/app/templates/import_app/fragments/profiles/list_presets.html index ba22a00..5bc10ef 100644 --- a/app/templates/import_app/fragments/profiles/list_presets.html +++ b/app/templates/import_app/fragments/profiles/list_presets.html @@ -6,28 +6,28 @@ {% block body %} {% if presets %} -
{% translate 'Name' %}{% translate 'Version' %}{% translate 'Name' %}{% translate 'Version' %}
- {{ profile.name }}{{ profile.get_version_display }}{{ profile.name }}{{ profile.get_version_display }}