mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-05-03 14:04:27 +02:00
Compare commits
13 Commits
dev
...
fix-procra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d72ff3cdf5 | ||
|
|
63c69e5c6a | ||
|
|
78171183cc | ||
|
|
34a2b6bfd4 | ||
|
|
8fc11b0acf | ||
|
|
9a30a0d3c0 | ||
|
|
10eecd09ff | ||
|
|
2cfb3fb12e | ||
|
|
47af8b135b | ||
|
|
39d0e63375 | ||
|
|
792154eba2 | ||
|
|
e627dd50be | ||
|
|
be24ca014e |
29
.vscode/launch.json
vendored
Normal file
29
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Docker: Dev",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "docker compose --env-file .env -f docker-compose.dev.yml up --build",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"postDebugTask": "Docker: Dev Down"
|
||||
},
|
||||
{
|
||||
"name": "Docker: Dev (no rebuild)",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "docker compose --env-file .env -f docker-compose.dev.yml up",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"postDebugTask": "Docker: Dev Down"
|
||||
},
|
||||
{
|
||||
"name": "Docker: Prod",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "docker compose --env-file .prod.env -f docker-compose.prod.yml up --build",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"postDebugTask": "Docker: Prod Down"
|
||||
}
|
||||
]
|
||||
}
|
||||
119
.vscode/tasks.json
vendored
Normal file
119
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Docker: Dev",
|
||||
"type": "shell",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"compose",
|
||||
"--env-file",
|
||||
".env",
|
||||
"-f",
|
||||
"docker-compose.dev.yml",
|
||||
"up",
|
||||
"--build"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Docker: Dev (no rebuild)",
|
||||
"type": "shell",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"compose",
|
||||
"--env-file",
|
||||
".env",
|
||||
"-f",
|
||||
"docker-compose.dev.yml",
|
||||
"up"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Docker: Dev Refresh Vite Deps",
|
||||
"type": "shell",
|
||||
"command": "docker compose --env-file .env -f docker-compose.dev.yml rm -sfv vite; docker compose --env-file .env -f docker-compose.dev.yml up --build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Docker: Dev Down",
|
||||
"type": "shell",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"compose",
|
||||
"--env-file",
|
||||
".env",
|
||||
"-f",
|
||||
"docker-compose.dev.yml",
|
||||
"down"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Docker: Prod",
|
||||
"type": "shell",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"compose",
|
||||
"--env-file",
|
||||
".prod.env",
|
||||
"-f",
|
||||
"docker-compose.prod.yml",
|
||||
"up",
|
||||
"--build"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Docker: Prod Down",
|
||||
"type": "shell",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"compose",
|
||||
"--env-file",
|
||||
".prod.env",
|
||||
"-f",
|
||||
"docker-compose.prod.yml",
|
||||
"down"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Django: Runserver localhost:8000",
|
||||
"type": "shell",
|
||||
"command": "${command:python.interpreterPath}",
|
||||
"args": [
|
||||
"manage.py",
|
||||
"runserver",
|
||||
"localhost:8000"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/app",
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1"
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -90,10 +90,10 @@ class AccountBalanceAPITests(TestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_get_balance_unauthenticated(self):
|
||||
"""Test unauthenticated request returns 403"""
|
||||
"""Test unauthenticated request returns 401"""
|
||||
unauthenticated_client = APIClient()
|
||||
response = unauthenticated_client.get(
|
||||
f"/api/accounts/{self.account.id}/balance/"
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
@@ -159,7 +159,7 @@ column_mapping:
|
||||
self.assertIn("import_run_id", response.data)
|
||||
|
||||
def test_unauthenticated_request(self):
|
||||
"""Test unauthenticated request returns 403"""
|
||||
"""Test unauthenticated request returns 401"""
|
||||
unauthenticated_client = APIClient()
|
||||
|
||||
csv_content = b"date,description,amount\n2025-01-01,Test,100"
|
||||
@@ -173,7 +173,7 @@ column_mapping:
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
|
||||
@override_settings(
|
||||
@@ -266,11 +266,11 @@ column_mapping:
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_profiles_unauthenticated(self):
|
||||
"""Test unauthenticated request returns 403"""
|
||||
"""Test unauthenticated request returns 401"""
|
||||
unauthenticated_client = APIClient()
|
||||
response = unauthenticated_client.get("/api/import/profiles/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
|
||||
@override_settings(
|
||||
@@ -397,8 +397,8 @@ column_mapping:
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_runs_unauthenticated(self):
|
||||
"""Test unauthenticated request returns 403"""
|
||||
"""Test unauthenticated request returns 401"""
|
||||
unauthenticated_client = APIClient()
|
||||
response = unauthenticated_client.get("/api/import/runs/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
@@ -1,6 +1,47 @@
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
import procrastinate
|
||||
from django.db import close_old_connections
|
||||
|
||||
|
||||
_CONNECTION_CLEANUP_WRAPPED = "_wygiwyh_connection_cleanup_wrapped"
|
||||
|
||||
|
||||
def _wrap_task_with_django_connection_cleanup(task):
|
||||
if getattr(task.func, _CONNECTION_CLEANUP_WRAPPED, False):
|
||||
return
|
||||
|
||||
func = task.func
|
||||
|
||||
if inspect.iscoroutinefunction(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
async def async_wrapped(*args, **kwargs):
|
||||
close_old_connections()
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
finally:
|
||||
close_old_connections()
|
||||
|
||||
wrapped = async_wrapped
|
||||
else:
|
||||
|
||||
@functools.wraps(func)
|
||||
def sync_wrapped(*args, **kwargs):
|
||||
close_old_connections()
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
finally:
|
||||
close_old_connections()
|
||||
|
||||
wrapped = sync_wrapped
|
||||
|
||||
setattr(wrapped, _CONNECTION_CLEANUP_WRAPPED, True)
|
||||
task.func = wrapped
|
||||
|
||||
|
||||
def on_app_ready(app: procrastinate.App):
|
||||
"""This function is ran upon procrastinate initialization."""
|
||||
...
|
||||
for task in set(app.tasks.values()):
|
||||
_wrap_task_with_django_connection_cleanup(task)
|
||||
|
||||
1
app/apps/common/tests/__init__.py
Normal file
1
app/apps/common/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
89
app/apps/common/tests/test_procrastinate.py
Normal file
89
app/apps/common/tests/test_procrastinate.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
import procrastinate
|
||||
from django.db import connection
|
||||
from django.test import SimpleTestCase, TransactionTestCase
|
||||
from procrastinate.testing import InMemoryConnector
|
||||
|
||||
from apps.common.procrastinate import on_app_ready
|
||||
|
||||
|
||||
def make_app_with_task(func):
|
||||
app = procrastinate.App(connector=InMemoryConnector())
|
||||
task = app.task(name="sample_task")(func)
|
||||
|
||||
return app, task
|
||||
|
||||
|
||||
class ProcrastinateConnectionCleanupTests(SimpleTestCase):
|
||||
def test_app_ready_closes_old_connections_around_sync_tasks(self):
|
||||
calls = []
|
||||
|
||||
def sample_task(value):
|
||||
calls.append(("task", value))
|
||||
return value * 2
|
||||
|
||||
app, task = make_app_with_task(sample_task)
|
||||
|
||||
with patch(
|
||||
"apps.common.procrastinate.close_old_connections",
|
||||
create=True,
|
||||
side_effect=lambda: calls.append(("cleanup", None)),
|
||||
):
|
||||
on_app_ready(app)
|
||||
|
||||
result = task.func(3)
|
||||
|
||||
self.assertEqual(result, 6)
|
||||
self.assertEqual(
|
||||
calls,
|
||||
[
|
||||
("cleanup", None),
|
||||
("task", 3),
|
||||
("cleanup", None),
|
||||
],
|
||||
)
|
||||
|
||||
def test_app_ready_closes_old_connections_when_sync_task_raises(self):
|
||||
calls = []
|
||||
|
||||
def sample_task():
|
||||
calls.append(("task", None))
|
||||
raise RuntimeError("boom")
|
||||
|
||||
app, task = make_app_with_task(sample_task)
|
||||
|
||||
with patch(
|
||||
"apps.common.procrastinate.close_old_connections",
|
||||
create=True,
|
||||
side_effect=lambda: calls.append(("cleanup", None)),
|
||||
):
|
||||
on_app_ready(app)
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
task.func()
|
||||
|
||||
self.assertEqual(
|
||||
calls,
|
||||
[
|
||||
("cleanup", None),
|
||||
("task", None),
|
||||
("cleanup", None),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class ProcrastinateConnectionRecoveryTests(TransactionTestCase):
|
||||
def test_wrapped_task_recovers_from_closed_django_connection(self):
|
||||
def sample_task():
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("SELECT 1")
|
||||
return cursor.fetchone()[0]
|
||||
|
||||
app, task = make_app_with_task(sample_task)
|
||||
on_app_ready(app)
|
||||
|
||||
connection.ensure_connection()
|
||||
connection.connection.close()
|
||||
|
||||
self.assertEqual(task.func(), 1)
|
||||
@@ -365,7 +365,9 @@ def check_for_transaction_rules(
|
||||
|
||||
if processed_action.set_category:
|
||||
value = simple.eval(processed_action.set_category)
|
||||
if isinstance(value, int):
|
||||
if value is None:
|
||||
transaction.category = None
|
||||
elif isinstance(value, int):
|
||||
transaction.category = TransactionCategory.objects.get(id=value)
|
||||
else:
|
||||
transaction.category = TransactionCategory.objects.get(name=value)
|
||||
@@ -458,7 +460,9 @@ def check_for_transaction_rules(
|
||||
transaction.account = account
|
||||
|
||||
elif field == TransactionRuleAction.Field.category:
|
||||
if isinstance(new_value, int):
|
||||
if new_value is None:
|
||||
transaction.category = None
|
||||
elif isinstance(new_value, int):
|
||||
category = TransactionCategory.objects.get(id=new_value)
|
||||
transaction.category = category
|
||||
elif isinstance(new_value, str):
|
||||
|
||||
1
app/apps/rules/tests/__init__.py
Normal file
1
app/apps/rules/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
82
app/apps/rules/tests/test_tasks.py
Normal file
82
app/apps/rules/tests/test_tasks.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from apps.accounts.models import Account
|
||||
from apps.currencies.models import Currency
|
||||
from apps.rules.models import TransactionRule, UpdateOrCreateTransactionRuleAction
|
||||
from apps.rules.tasks import check_for_transaction_rules
|
||||
from apps.transactions.models import Transaction
|
||||
|
||||
|
||||
def run_check_for_transaction_rules_without_worker_wrapper(**kwargs):
|
||||
task_func = check_for_transaction_rules.func
|
||||
task_func = getattr(task_func, "__wrapped__", task_func)
|
||||
|
||||
return task_func(**kwargs)
|
||||
|
||||
|
||||
class CheckForTransactionRulesTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(
|
||||
email="rules@example.com",
|
||||
password="testpass123",
|
||||
)
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD",
|
||||
name="US Dollar",
|
||||
decimal_places=2,
|
||||
)
|
||||
self.account = Account.objects.create(
|
||||
name="Main Account",
|
||||
currency=self.currency,
|
||||
owner=self.user,
|
||||
)
|
||||
|
||||
@patch("apps.rules.signals.check_for_transaction_rules.defer")
|
||||
def test_update_or_create_action_can_clear_category_from_none_expression(
|
||||
self, mock_defer
|
||||
):
|
||||
source_transaction = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
amount=Decimal("10.00"),
|
||||
date=date(2026, 5, 4),
|
||||
reference_date=date(2026, 5, 1),
|
||||
description="Source without category",
|
||||
category=None,
|
||||
owner=self.user,
|
||||
)
|
||||
rule = TransactionRule.objects.create(
|
||||
active=True,
|
||||
on_create=False,
|
||||
on_update=True,
|
||||
name="Copy transaction",
|
||||
trigger="True",
|
||||
owner=self.user,
|
||||
)
|
||||
UpdateOrCreateTransactionRuleAction.objects.create(
|
||||
rule=rule,
|
||||
set_account="account_id",
|
||||
set_type="'EX'",
|
||||
set_date="date",
|
||||
set_reference_date="reference_date",
|
||||
set_amount="amount",
|
||||
set_description="'Generated transaction'",
|
||||
set_category="category_name",
|
||||
)
|
||||
|
||||
run_check_for_transaction_rules_without_worker_wrapper(
|
||||
instance_id=source_transaction.id,
|
||||
user_id=self.user.id,
|
||||
signal="transaction_updated",
|
||||
)
|
||||
|
||||
generated_transaction = Transaction.objects.get(
|
||||
description="Generated transaction"
|
||||
)
|
||||
self.assertIsNone(generated_transaction.category)
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-16 02:24+0000\n"
|
||||
"PO-Revision-Date: 2026-03-02 22:30+0000\n"
|
||||
"PO-Revision-Date: 2026-04-30 02:24+0000\n"
|
||||
"Last-Translator: Herculino Trotta <netotrotta@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) <https://translations.herculino.com/"
|
||||
"projects/wygiwyh/app/pt_BR/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.16.1\n"
|
||||
"X-Generator: Weblate 5.17\n"
|
||||
|
||||
#: apps/accounts/forms.py:24
|
||||
msgid "Group name"
|
||||
@@ -3059,7 +3059,7 @@ msgstr "Abr"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr "Mai"
|
||||
msgstr "Maio"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
</div>
|
||||
|
||||
{# Filter transactions form #}
|
||||
<div class="z-1" x-show="filterOpen" x-collapse>
|
||||
<div class="z-1" x-show="filterOpen" x-collapse x-cloak>
|
||||
<div class="card card-body bg-base-200 mt-2">
|
||||
<div class="text-right">
|
||||
<button class="btn btn-outline btn-error btn-sm w-fit"
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
</div>
|
||||
|
||||
{# Filter transactions form #}
|
||||
<div class="z-1" x-show="filterOpen" x-collapse>
|
||||
<div class="z-1" x-show="filterOpen" x-collapse x-cloak>
|
||||
<div class="card card-body bg-base-200 mt-2">
|
||||
<div class="text-right">
|
||||
<button class="btn btn-outline btn-error btn-sm w-fit"
|
||||
|
||||
@@ -2,9 +2,9 @@ FROM node:lts-alpine
|
||||
|
||||
WORKDIR /usr/src/frontend
|
||||
|
||||
COPY ./frontend/package.json .
|
||||
COPY ./frontend/package.json ./frontend/package-lock.json ./
|
||||
|
||||
RUN npm install --verbose && npm cache clean --force
|
||||
RUN npm ci --verbose && npm cache clean --force
|
||||
|
||||
ENV PATH ./node_modules/.bin/:$PATH
|
||||
|
||||
|
||||
25
frontend/package-lock.json
generated
25
frontend/package-lock.json
generated
@@ -23,7 +23,7 @@
|
||||
"bootstrap": "^5.3.8",
|
||||
"chart.js": "^4.5.1",
|
||||
"chartjs-chart-sankey": "^0.14.0",
|
||||
"daisyui": "^5.5.5",
|
||||
"daisyui": "5.5.19",
|
||||
"htmx.org": "^2.0.8",
|
||||
"hyperscript.org": "^0.9.14",
|
||||
"mathjs": "^15.2.0",
|
||||
@@ -1667,12 +1667,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.8.25",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz",
|
||||
"integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==",
|
||||
"version": "2.10.24",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.24.tgz",
|
||||
"integrity": "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
"baseline-browser-mapping": "dist/cli.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
@@ -1743,9 +1746,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001754",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz",
|
||||
"integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==",
|
||||
"version": "1.0.30001791",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz",
|
||||
"integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -1816,9 +1819,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/daisyui": {
|
||||
"version": "5.5.5",
|
||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.5.tgz",
|
||||
"integrity": "sha512-ekvI93ZkWIJoCOtDl0D2QMxnWvTejk9V5nWBqRv+7t0xjiBXqAK5U6o6JE2RPvlIC3EqwNyUoIZSdHX9MZK3nw==",
|
||||
"version": "5.5.19",
|
||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.19.tgz",
|
||||
"integrity": "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/saadeghi/daisyui?sponsor=1"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"bootstrap": "^5.3.8",
|
||||
"chart.js": "^4.5.1",
|
||||
"chartjs-chart-sankey": "^0.14.0",
|
||||
"daisyui": "^5.5.5",
|
||||
"daisyui": "5.5.19",
|
||||
"htmx.org": "^2.0.8",
|
||||
"hyperscript.org": "^0.9.14",
|
||||
"mathjs": "^15.2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'hyperscript.org';
|
||||
import _hyperscript from 'hyperscript.org';
|
||||
import './_htmx.js';
|
||||
import Alpine from "alpinejs";
|
||||
import mask from '@alpinejs/mask';
|
||||
@@ -6,8 +6,10 @@ import collapse from '@alpinejs/collapse'
|
||||
import { create, all } from 'mathjs';
|
||||
|
||||
window.Alpine = Alpine;
|
||||
const _hyperscript = window._hyperscript;
|
||||
window._hyperscript = _hyperscript;
|
||||
if (!window._hyperscript) {
|
||||
window._hyperscript = _hyperscript;
|
||||
_hyperscript.browserInit();
|
||||
}
|
||||
window.math = create(all, {
|
||||
number: 'BigNumber',
|
||||
});
|
||||
|
||||
3
frontend/src/plugins/tw-bootstrap-grid-plugin.js
Normal file
3
frontend/src/plugins/tw-bootstrap-grid-plugin.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import twBootstrapGrid from "tw-bootstrap-grid";
|
||||
|
||||
export default twBootstrapGrid;
|
||||
@@ -4,7 +4,7 @@
|
||||
themes: wygiwyh_dark --default, wygiwyh_light;
|
||||
logs: true;
|
||||
}
|
||||
@plugin "tw-bootstrap-grid";
|
||||
@plugin "../plugins/tw-bootstrap-grid-plugin.js";
|
||||
|
||||
@plugin "daisyui/theme" {
|
||||
name: "wygiwyh_light";
|
||||
|
||||
Reference in New Issue
Block a user