remove old stacks
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1 +1,5 @@
|
|||||||
*.bundle
|
/target/
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite-wal
|
||||||
|
*.sqlite-shm
|
||||||
|
*.sqlite-journal
|
||||||
|
|||||||
12
.sqlx/query-4017d92f0898c5046c4fbe1cd440ca73e5eb5d0794c679c9e5f05eb87d1defca.json
generated
Normal file
12
.sqlx/query-4017d92f0898c5046c4fbe1cd440ca73e5eb5d0794c679c9e5f05eb87d1defca.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "INSERT INTO trips_items (\n item_id, \n trip_id, \n pick, \n pack, \n ready,\n new,\n user_id\n ) SELECT \n item_id,\n $1 as trip_id,\n pick,\n false as pack,\n false as ready,\n false as new,\n user_id\n FROM trips_items\n WHERE trip_id = $2 AND user_id = $3",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 3
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "4017d92f0898c5046c4fbe1cd440ca73e5eb5d0794c679c9e5f05eb87d1defca"
|
||||||
|
}
|
||||||
12
.sqlx/query-905a4518c657a01831fead855bad141d34f699c58b6aa5bee492b6eef2115d74.json
generated
Normal file
12
.sqlx/query-905a4518c657a01831fead855bad141d34f699c58b6aa5bee492b6eef2115d74.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "INSERT INTO trips_items (\n item_id, \n trip_id, \n pick, \n pack, \n ready,\n new,\n user_id\n ) SELECT \n id as item_id,\n $1 as trip_id,\n false as pick,\n false as pack,\n false as ready,\n false as new,\n user_id\n FROM inventory_items\n WHERE user_id = $2",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "905a4518c657a01831fead855bad141d34f699c58b6aa5bee492b6eef2115d74"
|
||||||
|
}
|
||||||
0
rust/Cargo.lock → Cargo.lock
generated
0
rust/Cargo.lock → Cargo.lock
generated
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
1
migrations/20230911175138_todos.sql
Normal file
1
migrations/20230911175138_todos.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-- Add migration script here
|
||||||
7
python_flask/.gitignore
vendored
7
python_flask/.gitignore
vendored
@@ -1,7 +0,0 @@
|
|||||||
__pycache__/
|
|
||||||
/venv/
|
|
||||||
*.sqlite
|
|
||||||
*.sqlite3
|
|
||||||
*.bak
|
|
||||||
*.bundle
|
|
||||||
/*.sqlite
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# ideas
|
|
||||||
|
|
||||||
Trip info:
|
|
||||||
* Itinerary
|
|
||||||
* Members
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Item info:
|
|
||||||
|
|
||||||
Comments
|
|
||||||
Links
|
|
||||||
n:1 Product
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Item groups that can be selected together. 1:1 product.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
State management.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Item comments per trip (that are added to item overview page)
|
|
||||||
|
|
||||||
"This item was already on the following trips:"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Todos, with preparation time window.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Review when setting to "done", review per item and for the whole trip.
|
|
||||||
|
|
||||||
"Would take again" (default yes)
|
|
||||||
|
|
||||||
# todos
|
|
||||||
|
|
||||||
Category CRUD
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Single-database configuration for Flask.
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# A generic, single database configuration.
|
|
||||||
|
|
||||||
[alembic]
|
|
||||||
# template used to generate migration files
|
|
||||||
# file_template = %%(rev)s_%%(slug)s
|
|
||||||
|
|
||||||
# set to 'true' to run the environment during
|
|
||||||
# the 'revision' command, regardless of autogenerate
|
|
||||||
# revision_environment = false
|
|
||||||
|
|
||||||
|
|
||||||
# Logging configuration
|
|
||||||
[loggers]
|
|
||||||
keys = root,sqlalchemy,alembic,flask_migrate
|
|
||||||
|
|
||||||
[handlers]
|
|
||||||
keys = console
|
|
||||||
|
|
||||||
[formatters]
|
|
||||||
keys = generic
|
|
||||||
|
|
||||||
[logger_root]
|
|
||||||
level = WARN
|
|
||||||
handlers = console
|
|
||||||
qualname =
|
|
||||||
|
|
||||||
[logger_sqlalchemy]
|
|
||||||
level = WARN
|
|
||||||
handlers =
|
|
||||||
qualname = sqlalchemy.engine
|
|
||||||
|
|
||||||
[logger_alembic]
|
|
||||||
level = INFO
|
|
||||||
handlers =
|
|
||||||
qualname = alembic
|
|
||||||
|
|
||||||
[logger_flask_migrate]
|
|
||||||
level = INFO
|
|
||||||
handlers =
|
|
||||||
qualname = flask_migrate
|
|
||||||
|
|
||||||
[handler_console]
|
|
||||||
class = StreamHandler
|
|
||||||
args = (sys.stderr,)
|
|
||||||
level = NOTSET
|
|
||||||
formatter = generic
|
|
||||||
|
|
||||||
[formatter_generic]
|
|
||||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
|
||||||
datefmt = %H:%M:%S
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
from __future__ import with_statement
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from logging.config import fileConfig
|
|
||||||
|
|
||||||
from flask import current_app
|
|
||||||
|
|
||||||
from alembic import context
|
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
|
||||||
# access to the values within the .ini file in use.
|
|
||||||
config = context.config
|
|
||||||
|
|
||||||
# Interpret the config file for Python logging.
|
|
||||||
# This line sets up loggers basically.
|
|
||||||
fileConfig(config.config_file_name)
|
|
||||||
logger = logging.getLogger('alembic.env')
|
|
||||||
|
|
||||||
# add your model's MetaData object here
|
|
||||||
# for 'autogenerate' support
|
|
||||||
# from myapp import mymodel
|
|
||||||
# target_metadata = mymodel.Base.metadata
|
|
||||||
config.set_main_option(
|
|
||||||
'sqlalchemy.url',
|
|
||||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
|
||||||
'%', '%%'))
|
|
||||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
|
||||||
# can be acquired:
|
|
||||||
# my_important_option = config.get_main_option("my_important_option")
|
|
||||||
# ... etc.
|
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline():
|
|
||||||
"""Run migrations in 'offline' mode.
|
|
||||||
|
|
||||||
This configures the context with just a URL
|
|
||||||
and not an Engine, though an Engine is acceptable
|
|
||||||
here as well. By skipping the Engine creation
|
|
||||||
we don't even need a DBAPI to be available.
|
|
||||||
|
|
||||||
Calls to context.execute() here emit the given string to the
|
|
||||||
script output.
|
|
||||||
|
|
||||||
"""
|
|
||||||
url = config.get_main_option("sqlalchemy.url")
|
|
||||||
context.configure(
|
|
||||||
url=url, target_metadata=target_metadata, literal_binds=True
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
|
||||||
context.run_migrations()
|
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_online():
|
|
||||||
"""Run migrations in 'online' mode.
|
|
||||||
|
|
||||||
In this scenario we need to create an Engine
|
|
||||||
and associate a connection with the context.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# this callback is used to prevent an auto-migration from being generated
|
|
||||||
# when there are no changes to the schema
|
|
||||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
|
||||||
def process_revision_directives(context, revision, directives):
|
|
||||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
|
||||||
script = directives[0]
|
|
||||||
if script.upgrade_ops.is_empty():
|
|
||||||
directives[:] = []
|
|
||||||
logger.info('No changes in schema detected.')
|
|
||||||
|
|
||||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
|
||||||
|
|
||||||
with connectable.connect() as connection:
|
|
||||||
context.configure(
|
|
||||||
connection=connection,
|
|
||||||
target_metadata=target_metadata,
|
|
||||||
process_revision_directives=process_revision_directives,
|
|
||||||
**current_app.extensions['migrate'].configure_args
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
|
||||||
context.run_migrations()
|
|
||||||
|
|
||||||
|
|
||||||
if context.is_offline_mode():
|
|
||||||
run_migrations_offline()
|
|
||||||
else:
|
|
||||||
run_migrations_online()
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
"""${message}
|
|
||||||
|
|
||||||
Revision ID: ${up_revision}
|
|
||||||
Revises: ${down_revision | comma,n}
|
|
||||||
Create Date: ${create_date}
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
${imports if imports else ""}
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = ${repr(up_revision)}
|
|
||||||
down_revision = ${repr(down_revision)}
|
|
||||||
branch_labels = ${repr(branch_labels)}
|
|
||||||
depends_on = ${repr(depends_on)}
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
${upgrades if upgrades else "pass"}
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
${downgrades if downgrades else "pass"}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"""empty message
|
|
||||||
|
|
||||||
Revision ID: 4e1894be1cca
|
|
||||||
Revises: 8593f77d68a3
|
|
||||||
Create Date: 2022-09-21 16:13:06.405648
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '4e1894be1cca'
|
|
||||||
down_revision = '8593f77d68a3'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_table('trip_to_triptype')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.create_table('trip_to_triptype',
|
|
||||||
sa.Column('trip_id', sa.VARCHAR(length=36), nullable=False),
|
|
||||||
sa.Column('trip_type_id', sa.VARCHAR(length=36), nullable=False),
|
|
||||||
sa.ForeignKeyConstraint(['trip_id'], ['trips.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['trip_type_id'], ['triptypes.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('trip_id', 'trip_type_id')
|
|
||||||
)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"""empty message
|
|
||||||
|
|
||||||
Revision ID: 8593f77d68a3
|
|
||||||
Revises:
|
|
||||||
Create Date: 2022-09-21 16:11:14.063997
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = '8593f77d68a3'
|
|
||||||
down_revision = None
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.drop_table('trip_to_triptype')
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
op.create_table('trip_to_triptype',
|
|
||||||
sa.Column('trip_id', sa.VARCHAR(length=36), nullable=False),
|
|
||||||
sa.Column('trip_type_id', sa.VARCHAR(length=36), nullable=False),
|
|
||||||
sa.ForeignKeyConstraint(['trip_id'], ['trips.id'], ),
|
|
||||||
sa.ForeignKeyConstraint(['trip_type_id'], ['triptypes.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('trip_id', 'trip_type_id')
|
|
||||||
)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import uuid
|
|
||||||
import sqlalchemy
|
|
||||||
import csv
|
|
||||||
from flask import Flask
|
|
||||||
from flask_migrate import Migrate
|
|
||||||
|
|
||||||
from .helpers import *
|
|
||||||
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{app.root_path}/../items.sqlite"
|
|
||||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
migrate = Migrate(app, db, render_as_batch=True)
|
|
||||||
|
|
||||||
from packager.models import *
|
|
||||||
import packager.views
|
|
||||||
|
|
||||||
db.create_all()
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class Base:
|
|
||||||
def __init__(self, element, root_path, active_page=None):
|
|
||||||
doc = dominate.document(title="Packager")
|
|
||||||
with doc.head:
|
|
||||||
t.script(src="https://unpkg.com/htmx.org@1.7.0")
|
|
||||||
t.script(src="https://cdn.tailwindcss.com")
|
|
||||||
t.script(src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.js", defer=True)
|
|
||||||
t.link(
|
|
||||||
rel="stylesheet",
|
|
||||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css",
|
|
||||||
)
|
|
||||||
with doc:
|
|
||||||
t.script(raw(open(os.path.join(root_path, "js/app.js")).read()))
|
|
||||||
with t.header(
|
|
||||||
_class=cls(
|
|
||||||
"bg-gray-200",
|
|
||||||
"p-5",
|
|
||||||
"flex",
|
|
||||||
"flex-row",
|
|
||||||
"flex-nowrap",
|
|
||||||
"justify-between",
|
|
||||||
"items-center",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t.span("Packager", _class=cls("text-xl", "font-semibold"))
|
|
||||||
with t.nav(
|
|
||||||
_class=cls("grow", "flex", "flex-row", "justify-center", "gap-x-6")
|
|
||||||
):
|
|
||||||
basecls = ["text-lg"]
|
|
||||||
activecls = ["font-bold", "underline"]
|
|
||||||
t.a(
|
|
||||||
"Inventory",
|
|
||||||
href="/inventory/",
|
|
||||||
_class=cls(
|
|
||||||
*basecls, *(activecls if active_page == "inventory" else [])
|
|
||||||
),
|
|
||||||
)
|
|
||||||
t.a(
|
|
||||||
"Trips",
|
|
||||||
href="/trips/",
|
|
||||||
_class=cls(
|
|
||||||
*basecls, *(activecls if active_page == "trips" else [])
|
|
||||||
),
|
|
||||||
)
|
|
||||||
doc.add(element.doc)
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class Home:
|
|
||||||
def __init__(self):
|
|
||||||
with t.div(id="home", _class=cls("p-8", "max-w-xl")) as doc:
|
|
||||||
with t.p():
|
|
||||||
t.a("Inventory", href="/inventory/")
|
|
||||||
with t.p():
|
|
||||||
t.a("Trips", href="/trips/")
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
def InventoryCategoryList(categories):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Categories", _class=cls("text-2xl", "mb-5"))
|
|
||||||
with t.table(
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
with t.thead(_class=cls("bg-gray-200")):
|
|
||||||
t.tr(
|
|
||||||
t.th("Name", _class=cls("border", "p-2")),
|
|
||||||
t.th("Weight", _class=cls("border", "p-2")),
|
|
||||||
_class="h-10",
|
|
||||||
)
|
|
||||||
with t.tbody() as b:
|
|
||||||
biggest_category_weight = max(
|
|
||||||
[sum([i.weight for i in c.items]) for c in categories] or [0]
|
|
||||||
)
|
|
||||||
for category in categories:
|
|
||||||
with t.tr(
|
|
||||||
_class=cls("h-10", "hover:bg-purple-100", "m-3", "h-full")
|
|
||||||
) as doc:
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"p-0",
|
|
||||||
"m-0",
|
|
||||||
*["font-bold"] if category.active else [],
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t.a(
|
|
||||||
category.name,
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/inventory/category/{category.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
with t.td(
|
|
||||||
_class=cls("border", "p-0", "m-0"),
|
|
||||||
style="position:relative;",
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/inventory/category/{category.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
):
|
|
||||||
weight = sum([i.weight for i in category.items])
|
|
||||||
width = int(weight / biggest_category_weight * 100)
|
|
||||||
t.p(weight)
|
|
||||||
t.div(
|
|
||||||
_class=cls("bg-blue-600", "h-1.5"),
|
|
||||||
style=f"width: {width}%;position:absolute;left:0;bottom:0;right:0;",
|
|
||||||
)
|
|
||||||
# t.progress(max=biggest_category_weight, value=weight)
|
|
||||||
with t.tr(
|
|
||||||
_class=cls(
|
|
||||||
"h-10", "hover:bg-purple-200", "bg-gray-300", "font-bold"
|
|
||||||
)
|
|
||||||
) as doc:
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a("Sum", _class=cls("block", "p-2", "m-2"))
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
sum([sum([i.weight for i in c.items]) for c in categories]),
|
|
||||||
_class=cls("block", "p-2", "m-2"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return doc
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
import urllib
|
|
||||||
|
|
||||||
class InventoryItemInfoEditRow:
|
|
||||||
def __init__(self, baseurl, name, value, attribute, inputtype="text"):
|
|
||||||
|
|
||||||
with t.tr() as doc:
|
|
||||||
t.form(
|
|
||||||
id=f"edit-{attribute}",
|
|
||||||
action=urllib.parse.urljoin(baseurl, f"edit/{attribute}/submit/"),
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
with t.tr(_class=cls("h-full")):
|
|
||||||
t.td(name, _class=cls("border", "p-2", "h-full"))
|
|
||||||
with t.td(_class=cls("border", "p-0")):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-blue-200", "w-full", "h-full", "px-2"),
|
|
||||||
type=inputtype,
|
|
||||||
id="item-edit-name",
|
|
||||||
form=f"edit-{attribute}",
|
|
||||||
name=attribute,
|
|
||||||
value=value,
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
id=f"edit-{attribute}-abort",
|
|
||||||
):
|
|
||||||
with t.a(href=baseurl):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
|
||||||
with t.td(
|
|
||||||
id=f"edit-{attribute}-save",
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
with t.button(type="submit", form=f"edit-{attribute}"):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemInfoNormalRow:
|
|
||||||
def __init__(self, editable, baseurl, name, value, attribute):
|
|
||||||
with t.tr() as doc:
|
|
||||||
t.td(name, _class=cls("border", "p-2"))
|
|
||||||
t.td(value, _class=cls("border", "p-2"))
|
|
||||||
if editable:
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-blue-200",
|
|
||||||
"hover:bg-blue-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
if editable:
|
|
||||||
with t.a(
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit",
|
|
||||||
href=f"?edit={attribute}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemInfo:
|
|
||||||
def __init__(self, item, edit, baseurl):
|
|
||||||
with t.table(
|
|
||||||
id="trip-table",
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
),
|
|
||||||
) as doc:
|
|
||||||
with t.tbody() as b:
|
|
||||||
if edit == "name":
|
|
||||||
InventoryItemInfoEditRow(baseurl, "Name", item.name, "name")
|
|
||||||
else:
|
|
||||||
InventoryItemInfoNormalRow(
|
|
||||||
True, baseurl, "Name", item.name, "name"
|
|
||||||
)
|
|
||||||
|
|
||||||
if edit == "weight":
|
|
||||||
InventoryItemInfoEditRow(
|
|
||||||
baseurl,
|
|
||||||
"Weight",
|
|
||||||
str(item.weight),
|
|
||||||
"weight",
|
|
||||||
inputtype="number",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
InventoryItemInfoNormalRow(
|
|
||||||
True, baseurl, "Weight", str(item.weight), "weight"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemDetails:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
item, edit, baseurl
|
|
||||||
):
|
|
||||||
with t.div(_class=cls("p-8")
|
|
||||||
) as doc:
|
|
||||||
t.h1("Item", _class=cls("text-2xl", "font-semibold"))
|
|
||||||
with t.div(_class=cls("my-6")):
|
|
||||||
InventoryItemInfo(item, edit, baseurl)
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemRowEdit(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-100")) as doc:
|
|
||||||
with t.td(colspan=2, _class=cls("border-none", "bg-purple-100", "h-10")):
|
|
||||||
with t.div():
|
|
||||||
t.form(
|
|
||||||
id="edit-item",
|
|
||||||
action=f"/inventory/item/{item.id}/edit/submit/",
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
|
||||||
with t.span(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"border-1",
|
|
||||||
"border-purple-500",
|
|
||||||
"bg-purple-100",
|
|
||||||
"mr-1",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-purple-100", "w-full", "h-full", "px-2"),
|
|
||||||
type="text",
|
|
||||||
id="item-edit-name",
|
|
||||||
form="edit-item",
|
|
||||||
name="name",
|
|
||||||
value=item.name,
|
|
||||||
**{
|
|
||||||
"x-on:input": "edit_submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
with t.span(
|
|
||||||
_class=cls(
|
|
||||||
"border", "border-1", "border-purple-500", "bg-purple-100"
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-purple-100", "w-full", "h-full", "px-2"),
|
|
||||||
type="text",
|
|
||||||
id="item-edit-weight",
|
|
||||||
name="weight",
|
|
||||||
form="edit-item",
|
|
||||||
value=item.weight,
|
|
||||||
)
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
id="edit-item-abort",
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
href=f"/inventory/category/{item.category.id}",
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit/cancel",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
|
||||||
with t.td(
|
|
||||||
id="edit-item-save",
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
# **{
|
|
||||||
# "x-bind:class": 'edit_submit_enabled || "cursor-not-allowed opacity-50"',
|
|
||||||
# "x-on:htmx:before-request": "(e) => edit_submit_enabled || e.preventDefault()",
|
|
||||||
# },
|
|
||||||
):
|
|
||||||
with t.button(type="submit", form="edit-item"):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemRowNormal(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-100")) as doc:
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
item.name,
|
|
||||||
href=f"/inventory/item/{item.id}/",
|
|
||||||
_class=cls("p-2", "w-full", "inline-block"),
|
|
||||||
)
|
|
||||||
width = int(item.weight / biggest_item_weight * 100)
|
|
||||||
with t.td(_class=cls("border", "px-2"), style="position:relative;"):
|
|
||||||
t.p(str(item.weight))
|
|
||||||
t.div(
|
|
||||||
_class=cls("bg-blue-600", "h-1.5"),
|
|
||||||
style=";".join(
|
|
||||||
[
|
|
||||||
f"width: {width}%",
|
|
||||||
"position:absolute",
|
|
||||||
"left:0",
|
|
||||||
"bottom:0",
|
|
||||||
"right:0",
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-blue-200",
|
|
||||||
"hover:bg-blue-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit",
|
|
||||||
href=f"?edit={item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
id="start-edit-item",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
# data_hx_delete=f"/item/{item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
href=f"/inventory/item/{item.id}/delete"
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-delete", "text-xl"))
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemRow(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
if item.edit:
|
|
||||||
self.doc = InventoryItemRowEdit(item, biggest_item_weight)
|
|
||||||
else:
|
|
||||||
self.doc = InventoryItemRowNormal(item, biggest_item_weight)
|
|
||||||
|
|
||||||
|
|
||||||
def InventoryItemList(items):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Items", _class=cls("text-2xl", "mb-5"))
|
|
||||||
with t.table(
|
|
||||||
id="item-table",
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
with t.thead(_class=cls("bg-gray-200")):
|
|
||||||
t.tr(
|
|
||||||
t.th("Name", _class=cls("border", "p-2")),
|
|
||||||
t.th("Weight", _class=cls("border", "p-2")),
|
|
||||||
_class="h-10",
|
|
||||||
)
|
|
||||||
with t.tbody() as b:
|
|
||||||
biggest_item_weight = max([i.weight for i in items] or [0])
|
|
||||||
if biggest_item_weight <= 0:
|
|
||||||
biggest_item_weight = 1
|
|
||||||
for item in items:
|
|
||||||
InventoryItemRow(item, biggest_item_weight).doc
|
|
||||||
|
|
||||||
return doc
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from .InventoryItemList import InventoryItemList
|
|
||||||
from .InventoryCategoryList import InventoryCategoryList
|
|
||||||
from .InventoryNewItem import InventoryNewItem
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemManager:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
categories,
|
|
||||||
items,
|
|
||||||
active_category,
|
|
||||||
name=None,
|
|
||||||
description=None,
|
|
||||||
error=False,
|
|
||||||
errormsg=None,
|
|
||||||
):
|
|
||||||
assert not (error and not errormsg)
|
|
||||||
with t.div(
|
|
||||||
id="pkglist-item-manager", _class=cls("p-8", "grid", "grid-cols-4", "gap-3")
|
|
||||||
) as doc:
|
|
||||||
with t.div(_class=cls("col-span-2")):
|
|
||||||
InventoryCategoryList(categories),
|
|
||||||
with t.div(_class=cls("col-span-2")):
|
|
||||||
InventoryItemList(items),
|
|
||||||
InventoryNewItem(categories, active_category)
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
def InventoryNewItem(categories, active_category, name=None, weight=None):
|
|
||||||
with t.form(
|
|
||||||
id="new-item",
|
|
||||||
name="new_item",
|
|
||||||
# data_hx_post="/list/",
|
|
||||||
# data_hx_target="#item-manager",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
action="/inventory/item/",
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
_class=cls("mt-8", "p-5", "border-2", "border-gray-200"),
|
|
||||||
# **{
|
|
||||||
# "x-on:htmx:before-request": "(e) => submit_enabled || e.preventDefault()",
|
|
||||||
# "x-data": alpinedata(
|
|
||||||
# {
|
|
||||||
# "submit_enabled": (
|
|
||||||
# jsbool(not error)
|
|
||||||
# + '&& document.getElementById("listname").value.trim().length !== 0'
|
|
||||||
# )
|
|
||||||
# }
|
|
||||||
# ),
|
|
||||||
# },
|
|
||||||
) as doc:
|
|
||||||
with t.div(_class=cls("mb-5", "flex", "flex-row", "items-center")):
|
|
||||||
t.span(_class=cls("mdi", "mdi-playlist-plus", "text-2xl", "mr-4"))
|
|
||||||
t.p("Add new item", _class=cls("inline", "text-xl"))
|
|
||||||
with t.div(_class=cls("w-11/12", "mx-auto")):
|
|
||||||
with t.div(_class=cls("pb-8")):
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "items-start")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"Name",
|
|
||||||
_for="item-name",
|
|
||||||
_class=cls("font-bold", "w-1/2", "p-2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
t._input(
|
|
||||||
type="text",
|
|
||||||
id="item-name",
|
|
||||||
name="name",
|
|
||||||
**{"value": name} if name is not None else {},
|
|
||||||
# data_hx_target="#new-item",
|
|
||||||
# data_hx_post="/item/name/validate",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
# data_hx_trigger="changed",
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
# "appearance-none" if error else None,
|
|
||||||
"border-2",
|
|
||||||
# "border-red-400" if error else "border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
# "focus:border-purple-500" if not error else None,
|
|
||||||
),
|
|
||||||
# **{
|
|
||||||
# "x-on:input": "submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
|
||||||
# },
|
|
||||||
)
|
|
||||||
# t.p(
|
|
||||||
# errormsg, _class=cls("mt-1", "text-red-400", "text-sm")
|
|
||||||
# ) if error else None
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "items-center", "pb-8")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"Weight",
|
|
||||||
_for="item-weight",
|
|
||||||
_class=cls("font-bold", "w-1/2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
t._input(
|
|
||||||
type="text",
|
|
||||||
id="item-weight",
|
|
||||||
name="weight",
|
|
||||||
**{"value": weight} if weight is not None else {},
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
"appearance-none",
|
|
||||||
"border-2",
|
|
||||||
"border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
"focus:border-purple-500",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "items-center", "pb-8")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"Category",
|
|
||||||
_for="item-category",
|
|
||||||
_class=cls("font-bold", "w-1/2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
with t.select(
|
|
||||||
id="item-category",
|
|
||||||
name="category",
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
# "appearance-none",
|
|
||||||
"border-2",
|
|
||||||
"border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
"focus:border-purple-500",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
for category in categories:
|
|
||||||
if active_category and category.id == active_category.id:
|
|
||||||
t.option(
|
|
||||||
category.name, value=category.id, selected=True
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
t.option(category.name, value=category.id)
|
|
||||||
t._input(
|
|
||||||
type="submit",
|
|
||||||
value="Add",
|
|
||||||
# **{
|
|
||||||
# "x-bind:class": 'submit_enabled ? "cursor-pointer" : "cursor-not-allowed opacity-50"'
|
|
||||||
# },
|
|
||||||
_class=cls(
|
|
||||||
"py-2",
|
|
||||||
"border-2",
|
|
||||||
"rounded",
|
|
||||||
"border-gray-300",
|
|
||||||
"mx-auto",
|
|
||||||
"w-full",
|
|
||||||
# "hover:border-purple-500" if not error else None,
|
|
||||||
# "hover:bg-purple-200" if not error else None,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return doc
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
def NewTrip(name=None):
|
|
||||||
with t.form(
|
|
||||||
id="new-trip",
|
|
||||||
name="new_trip",
|
|
||||||
# data_hx_post="/list/",
|
|
||||||
# data_hx_target="#trip-manager",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
action="/trip/",
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
_class=cls("mt-8", "p-5", "border-2", "border-gray-200"),
|
|
||||||
# **{
|
|
||||||
# "x-on:htmx:before-request": "(e) => submit_enabled || e.preventDefault()",
|
|
||||||
# "x-data": alpinedata(
|
|
||||||
# {
|
|
||||||
# "submit_enabled": (
|
|
||||||
# jsbool(not error)
|
|
||||||
# + '&& document.getElementById("listname").value.trim().length !== 0'
|
|
||||||
# )
|
|
||||||
# }
|
|
||||||
# ),
|
|
||||||
# },
|
|
||||||
) as doc:
|
|
||||||
with t.div(_class=cls("mb-5", "flex", "flex-row", "trips-center")):
|
|
||||||
t.span(_class=cls("mdi", "mdi-playlist-plus", "text-2xl", "mr-4"))
|
|
||||||
t.p("Add new trip", _class=cls("inline", "text-xl"))
|
|
||||||
with t.div(_class=cls("w-11/12", "mx-auto")):
|
|
||||||
with t.div(_class=cls("pb-8")):
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "trips-start")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"Name",
|
|
||||||
_for="trip-name",
|
|
||||||
_class=cls("font-bold", "w-1/2", "p-2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
t._input(
|
|
||||||
type="text",
|
|
||||||
id="trip-name",
|
|
||||||
name="name",
|
|
||||||
**{"value": name} if name is not None else {},
|
|
||||||
# data_hx_target="#new-trip",
|
|
||||||
# data_hx_post="/trip/name/validate",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
# data_hx_trigger="changed",
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
# "appearance-none" if error else None,
|
|
||||||
"border-2",
|
|
||||||
# "border-red-400" if error else "border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
# "focus:border-purple-500" if not error else None,
|
|
||||||
),
|
|
||||||
# **{
|
|
||||||
# "x-on:input": "submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
|
||||||
# },
|
|
||||||
)
|
|
||||||
# t.p(
|
|
||||||
# errormsg, _class=cls("mt-1", "text-red-400", "text-sm")
|
|
||||||
# ) if error else None
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "trips-center", "pb-8")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"Start date",
|
|
||||||
_for="start-date",
|
|
||||||
_class=cls("font-bold", "w-1/2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
t._input(
|
|
||||||
type="date",
|
|
||||||
id="start-date",
|
|
||||||
name="start-date",
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
"appearance-none",
|
|
||||||
"border-2",
|
|
||||||
"border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
"focus:border-purple-500",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
with t.div(
|
|
||||||
_class=cls("flex", "flex-row", "justify-center", "trips-center", "pb-8")
|
|
||||||
):
|
|
||||||
t.label(
|
|
||||||
"End date",
|
|
||||||
_for="end-date",
|
|
||||||
_class=cls("font-bold", "w-1/2", "text-center"),
|
|
||||||
)
|
|
||||||
with t.span(_class=cls("w-1/2")):
|
|
||||||
t._input(
|
|
||||||
type="date",
|
|
||||||
id="end-date",
|
|
||||||
name="end-date",
|
|
||||||
_class=cls(
|
|
||||||
"block",
|
|
||||||
"w-full",
|
|
||||||
"p-2",
|
|
||||||
"bg-gray-50",
|
|
||||||
"appearance-none",
|
|
||||||
"border-2",
|
|
||||||
"border-gray-300",
|
|
||||||
"rounded",
|
|
||||||
"focus:outline-none",
|
|
||||||
"focus:bg-white",
|
|
||||||
"focus:border-purple-500",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
t._input(
|
|
||||||
type="submit",
|
|
||||||
value="Add",
|
|
||||||
# **{
|
|
||||||
# "x-bind:class": 'submit_enabled ? "cursor-pointer" : "cursor-not-allowed opacity-50"'
|
|
||||||
# },
|
|
||||||
_class=cls(
|
|
||||||
"py-2",
|
|
||||||
"border-2",
|
|
||||||
"rounded",
|
|
||||||
"border-gray-300",
|
|
||||||
"mx-auto",
|
|
||||||
"w-full",
|
|
||||||
# "hover:border-purple-500" if not error else None,
|
|
||||||
# "hover:bg-purple-200" if not error else None,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return doc
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class TripCategoryList:
|
|
||||||
def __init__(self, trip, categories):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Categories", _class=cls("text-xl", "mb-5"))
|
|
||||||
with t.table(
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
with t.thead(_class=cls("bg-gray-200")):
|
|
||||||
t.tr(
|
|
||||||
t.th("Name", _class=cls("border", "p-2")),
|
|
||||||
t.th("Weight", _class=cls("border", "p-2")),
|
|
||||||
t.th("Max", _class=cls("border", "p-2")),
|
|
||||||
_class="h-10",
|
|
||||||
)
|
|
||||||
with t.tbody() as b:
|
|
||||||
for category in categories:
|
|
||||||
items = [
|
|
||||||
i
|
|
||||||
for i in trip.items
|
|
||||||
if i.inventory_item.category_id == category.id
|
|
||||||
]
|
|
||||||
biggest_category_weight = 1
|
|
||||||
|
|
||||||
for cat in categories:
|
|
||||||
category_items = [
|
|
||||||
i
|
|
||||||
for i in trip.items
|
|
||||||
if i.inventory_item.category_id == cat.id
|
|
||||||
]
|
|
||||||
weight_sum = sum(
|
|
||||||
[
|
|
||||||
i.inventory_item.weight
|
|
||||||
for i in category_items
|
|
||||||
if i.pick
|
|
||||||
]
|
|
||||||
)
|
|
||||||
if weight_sum > biggest_category_weight:
|
|
||||||
biggest_category_weight = weight_sum
|
|
||||||
|
|
||||||
weight = sum([i.inventory_item.weight for i in items if i.pick])
|
|
||||||
|
|
||||||
with t.tr(
|
|
||||||
_class=cls(
|
|
||||||
"h-10",
|
|
||||||
"hover:bg-purple-100",
|
|
||||||
"m-3",
|
|
||||||
"h-full",
|
|
||||||
*["bg-blue-100"]
|
|
||||||
if category.active
|
|
||||||
else (
|
|
||||||
["bg-red-100"]
|
|
||||||
if any([i.pick != i.pack for i in items])
|
|
||||||
else []
|
|
||||||
),
|
|
||||||
)
|
|
||||||
) as doc:
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"p-0",
|
|
||||||
"m-0",
|
|
||||||
*["font-bold"] if category.active else [],
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t.a(
|
|
||||||
category.name,
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}/category/{category.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.td(
|
|
||||||
_class=cls("border", "p-0", "m-0"),
|
|
||||||
style="position:relative;",
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/category/{category.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
):
|
|
||||||
width = int(weight / biggest_category_weight * 100)
|
|
||||||
t.p(weight)
|
|
||||||
t.div(
|
|
||||||
_class=cls("bg-blue-600", "h-1.5"),
|
|
||||||
style=f"width: {width}%;position:absolute;left:0;bottom:0;right:0;",
|
|
||||||
)
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
sum([i.inventory_item.weight for i in items]),
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/category/{category.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
# with t.tr(_class=cls("h-10", "hover:bg-purple-200", "bg-gray-300", "font-bold")) as doc:
|
|
||||||
# with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
# t.a(
|
|
||||||
# "Sum",
|
|
||||||
# _class=cls("block", "p-2", "m-2"),
|
|
||||||
# )
|
|
||||||
# with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
# t.a(
|
|
||||||
# sum(([i.inventory_item.weight for i in c.items]) for c in categories]),
|
|
||||||
# _class=cls("block", "p-2", "m-2"),
|
|
||||||
# )
|
|
||||||
# with t.td(_class=cls("border", "p-0", "m-0", "font-normal")):
|
|
||||||
# t.a(
|
|
||||||
# sum(([i.inventory_item.weight for i in c.items]) for c in categories]),
|
|
||||||
# _class=cls("block", "p-2", "m-2"),
|
|
||||||
# )
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class TripItemRowEdit(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-100")) as doc:
|
|
||||||
with t.td(_class=cls("border")):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"?item_{'unpick' if item.pick else 'pick'}={item.inventory_item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls(
|
|
||||||
"inline-block",
|
|
||||||
"p-2",
|
|
||||||
"m-0",
|
|
||||||
"w-full",
|
|
||||||
"flex",
|
|
||||||
"justify-center",
|
|
||||||
"content-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
type="checkbox", **({"checked": True} if item.pick else {})
|
|
||||||
)
|
|
||||||
with t.td(_class=cls("border")):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"?item_{'unpack' if item.pack else 'pack'}={item.inventory_item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls(
|
|
||||||
"inline-block",
|
|
||||||
"p-2",
|
|
||||||
"m-0",
|
|
||||||
"w-full",
|
|
||||||
"flex",
|
|
||||||
"justify-center",
|
|
||||||
"content-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
type="checkbox", **({"checked": True} if item.pack else {})
|
|
||||||
)
|
|
||||||
# with t.td(item.name, _class=cls("border", "px-2")),
|
|
||||||
with t.td(colspan=2, _class=cls("border-none", "bg-purple-100", "h-10")):
|
|
||||||
with t.div():
|
|
||||||
t.form(
|
|
||||||
id="edit-item",
|
|
||||||
action=f"/inventory/item/{item.inventory_item.id}/edit/submit/",
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
|
||||||
with t.span(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"border-1",
|
|
||||||
"border-purple-500",
|
|
||||||
"bg-purple-100",
|
|
||||||
"mr-1",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-purple-100", "w-full", "h-full", "px-2"),
|
|
||||||
type="text",
|
|
||||||
id="item-edit-name",
|
|
||||||
form="edit-item",
|
|
||||||
name="name",
|
|
||||||
value=item.name,
|
|
||||||
**{
|
|
||||||
"x-on:input": "edit_submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
with t.span(
|
|
||||||
_class=cls(
|
|
||||||
"border", "border-1", "border-purple-500", "bg-purple-100"
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-purple-100", "w-full", "h-full", "px-2"),
|
|
||||||
type="text",
|
|
||||||
id="item-edit-weight",
|
|
||||||
name="weight",
|
|
||||||
form="edit-item",
|
|
||||||
value=item.weight,
|
|
||||||
)
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
id="edit-item-abort",
|
|
||||||
):
|
|
||||||
with t.a(
|
|
||||||
href=f"/inventory/category/{item.category.id}",
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit/cancel",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
|
||||||
with t.td(
|
|
||||||
id="edit-item-save",
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
# **{
|
|
||||||
# "x-bind:class": 'edit_submit_enabled || "cursor-not-allowed opacity-50"',
|
|
||||||
# "x-on:htmx:before-request": "(e) => edit_submit_enabled || e.preventDefault()",
|
|
||||||
# },
|
|
||||||
):
|
|
||||||
with t.button(type="submit", form="edit-item"):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripItemRowNormal(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-100")) as doc:
|
|
||||||
with t.td(_class=cls("border")):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"?item_{'unpick' if item.pick else 'pick'}={item.inventory_item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls(
|
|
||||||
"inline-block",
|
|
||||||
"p-2",
|
|
||||||
"m-0",
|
|
||||||
"w-full",
|
|
||||||
"justify-center",
|
|
||||||
"content-center",
|
|
||||||
"flex",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
type="checkbox",
|
|
||||||
form=f"toggle-item-pick",
|
|
||||||
name="pick-{item.inventory_item.id}",
|
|
||||||
**({"checked": True} if item.pick else {}),
|
|
||||||
) # , xstyle="position: relative;z-index: 1;pointer-events: auto; ")
|
|
||||||
with t.td(_class=cls("border")):
|
|
||||||
with t.a(
|
|
||||||
id="select-category",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"?item_{'unpack' if item.pack else 'pack'}={item.inventory_item.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls(
|
|
||||||
"inline-block",
|
|
||||||
"p-2",
|
|
||||||
"m-0",
|
|
||||||
"w-full",
|
|
||||||
"flex",
|
|
||||||
"justify-center",
|
|
||||||
"content-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
t._input(
|
|
||||||
type="checkbox",
|
|
||||||
form=f"toggle-item-pack",
|
|
||||||
name="pack-{item.inventory_item.id}",
|
|
||||||
**({"checked": True} if item.pack else {}),
|
|
||||||
) # , xstyle="position: relative;z-index: 1;pointer-events: auto; ")
|
|
||||||
t.td(
|
|
||||||
item.inventory_item.name,
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"px-2",
|
|
||||||
*(("bg-red-100",) if item.pick != item.pack else ()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
width = int(item.inventory_item.weight / biggest_item_weight * 100)
|
|
||||||
with t.td(_class=cls("border", "px-2"), style="position:relative;"):
|
|
||||||
t.p(str(item.inventory_item.weight))
|
|
||||||
t.div(
|
|
||||||
_class=cls("bg-blue-600", "h-1.5"),
|
|
||||||
style=";".join(
|
|
||||||
[
|
|
||||||
f"width: {width}%",
|
|
||||||
"position:absolute",
|
|
||||||
"left:0",
|
|
||||||
"bottom:0",
|
|
||||||
"right:0",
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripItemRow(object):
|
|
||||||
def __init__(self, item, biggest_item_weight):
|
|
||||||
if item.edit:
|
|
||||||
self.doc = TripItemRowEdit(item, biggest_item_weight)
|
|
||||||
else:
|
|
||||||
self.doc = TripItemRowNormal(item, biggest_item_weight)
|
|
||||||
|
|
||||||
|
|
||||||
class TripItemList:
|
|
||||||
def __init__(self, trip, active_category):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Items", _class=cls("text-xl", "mb-5"))
|
|
||||||
with t.table(
|
|
||||||
id="item-table",
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
with t.thead(_class=cls("bg-gray-200")):
|
|
||||||
t.tr(
|
|
||||||
t.th("Take?", _class=cls("border", "p-2", "w-0")),
|
|
||||||
t.th("Packed?", _class=cls("border", "p-2", "w-0")),
|
|
||||||
t.th("Name", _class=cls("border", "p-2")),
|
|
||||||
t.th("Weight", _class=cls("border", "p-2")),
|
|
||||||
_class="h-10",
|
|
||||||
)
|
|
||||||
with t.tbody() as b:
|
|
||||||
if active_category:
|
|
||||||
biggest_item_weight = max(
|
|
||||||
[
|
|
||||||
i.inventory_item.weight
|
|
||||||
for i in trip.items
|
|
||||||
if i.inventory_item.category_id == active_category.id
|
|
||||||
]
|
|
||||||
or [0]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
biggest_item_weight = max(
|
|
||||||
[i.inventory_item.weight for i in trip.items] or [0]
|
|
||||||
)
|
|
||||||
if biggest_item_weight <= 0:
|
|
||||||
biggest_item_weight = 1
|
|
||||||
print(active_category)
|
|
||||||
for item in trip.items:
|
|
||||||
if (
|
|
||||||
not active_category
|
|
||||||
or item.inventory_item.category_id == active_category.id
|
|
||||||
):
|
|
||||||
TripItemRow(item, biggest_item_weight).doc
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from .TripCategoryList import TripCategoryList
|
|
||||||
from .TripItemList import TripItemList
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class TripItemManager:
|
|
||||||
def __init__(self, trip, categories, active_category):
|
|
||||||
with t.div(
|
|
||||||
id="pkglist-item-manager", _class=cls("grid", "grid-cols-4", "gap-3")
|
|
||||||
) as doc:
|
|
||||||
with t.div(_class=cls("col-span-2")):
|
|
||||||
TripCategoryList(trip, categories),
|
|
||||||
with t.div(_class=cls("col-span-2")):
|
|
||||||
TripItemList(trip, active_category=active_category),
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from .TripTable import TripTable
|
|
||||||
from .NewTrip import NewTrip
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class TripList:
|
|
||||||
def __init__(self, trips):
|
|
||||||
with t.div(id="trips-manager", _class=cls("p-8")) as doc:
|
|
||||||
TripTable(trips),
|
|
||||||
NewTrip(
|
|
||||||
# name=name, description=description, error=error, errormsg=errormsg
|
|
||||||
)
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,381 +0,0 @@
|
|||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
import urllib
|
|
||||||
import decimal
|
|
||||||
|
|
||||||
from .TripTable import TripTable
|
|
||||||
from .NewTrip import NewTrip
|
|
||||||
from .TripItemManager import TripItemManager
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
from ..models import TripState
|
|
||||||
|
|
||||||
|
|
||||||
class TripInfoEditRow:
|
|
||||||
def __init__(self, baseurl, name, value, attribute, inputtype="text"):
|
|
||||||
|
|
||||||
with t.tr() as doc:
|
|
||||||
t.form(
|
|
||||||
id=f"edit-{attribute}",
|
|
||||||
action=urllib.parse.urljoin(baseurl, f"edit/{attribute}/submit/"),
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
with t.tr(_class=cls("h-full")):
|
|
||||||
t.td(name, _class=cls("border", "p-2", "h-full"))
|
|
||||||
with t.td(_class=cls("border", "p-0")):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-blue-200", "w-full", "h-full", "px-2"),
|
|
||||||
type=inputtype,
|
|
||||||
id="item-edit-name",
|
|
||||||
form=f"edit-{attribute}",
|
|
||||||
name=attribute,
|
|
||||||
value=value,
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
id=f"edit-{attribute}-abort",
|
|
||||||
):
|
|
||||||
with t.a(href=baseurl):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
|
||||||
with t.td(
|
|
||||||
id=f"edit-{attribute}-save",
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
with t.button(type="submit", form=f"edit-{attribute}"):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripInfoNormalRow:
|
|
||||||
def __init__(self, editable, baseurl, name, value, attribute):
|
|
||||||
with t.tr() as doc:
|
|
||||||
t.td(name, _class=cls("border", "p-2"))
|
|
||||||
t.td(value, _class=cls("border", "p-2"))
|
|
||||||
if editable:
|
|
||||||
with t.td(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"bg-blue-200",
|
|
||||||
"hover:bg-blue-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"w-8",
|
|
||||||
"text-center",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
if editable:
|
|
||||||
with t.a(
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit",
|
|
||||||
href=f"?edit={attribute}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripInfo:
|
|
||||||
def __init__(self, trip, edit, baseurl, triptypes):
|
|
||||||
with t.table(
|
|
||||||
id="trip-table",
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
),
|
|
||||||
) as doc:
|
|
||||||
with t.tbody() as b:
|
|
||||||
TripInfoNormalRow(False, "", "State", trip.state.name, "")
|
|
||||||
|
|
||||||
if edit == "location":
|
|
||||||
TripInfoEditRow(baseurl, "Location", trip.location, "location")
|
|
||||||
else:
|
|
||||||
TripInfoNormalRow(
|
|
||||||
True, baseurl, "Location", trip.location, "location"
|
|
||||||
)
|
|
||||||
|
|
||||||
if edit == "start_date":
|
|
||||||
TripInfoEditRow(
|
|
||||||
baseurl,
|
|
||||||
"From",
|
|
||||||
str(trip.start_date),
|
|
||||||
"start_date",
|
|
||||||
inputtype="date",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
TripInfoNormalRow(
|
|
||||||
True, baseurl, "From", str(trip.start_date), "start_date"
|
|
||||||
)
|
|
||||||
|
|
||||||
if edit == "end_date":
|
|
||||||
TripInfoEditRow(
|
|
||||||
baseurl, "To", str(trip.end_date), "end_date", inputtype="date"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
TripInfoNormalRow(
|
|
||||||
True, baseurl, "To", str(trip.end_date), "end_date"
|
|
||||||
)
|
|
||||||
|
|
||||||
if edit == "temp_min":
|
|
||||||
TripInfoEditRow(
|
|
||||||
baseurl,
|
|
||||||
"Temp (min)",
|
|
||||||
trip.temp_min,
|
|
||||||
"temp_min",
|
|
||||||
inputtype="number",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
TripInfoNormalRow(
|
|
||||||
True, baseurl, "Temp (min)", trip.temp_min, "temp_min"
|
|
||||||
)
|
|
||||||
|
|
||||||
if edit == "temp_max":
|
|
||||||
TripInfoEditRow(
|
|
||||||
baseurl,
|
|
||||||
"Temp (max)",
|
|
||||||
trip.temp_max,
|
|
||||||
"temp_max",
|
|
||||||
inputtype="number",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
TripInfoNormalRow(
|
|
||||||
True, baseurl, "Temp (max)", trip.temp_max, "temp_max"
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.tr():
|
|
||||||
t.td(f"Types", _class=cls("border", "p-2"))
|
|
||||||
with t.td(_class=cls("border", "p-2")):
|
|
||||||
with t.ul(
|
|
||||||
_class=cls(
|
|
||||||
"flex",
|
|
||||||
"flex-row",
|
|
||||||
"flex-wrap",
|
|
||||||
"gap-2",
|
|
||||||
"justify-between",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
with t.div(
|
|
||||||
_class=cls(
|
|
||||||
"flex",
|
|
||||||
"flex-row",
|
|
||||||
"flex-wrap",
|
|
||||||
"gap-2",
|
|
||||||
"justify-start",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
for triptype in trip.types:
|
|
||||||
with t.a(href=f"?type_remove={triptype.id}"):
|
|
||||||
with t.li(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"rounded-2xl",
|
|
||||||
"py-0.5",
|
|
||||||
"px-2",
|
|
||||||
"bg-green-100",
|
|
||||||
"cursor-pointer",
|
|
||||||
"flex",
|
|
||||||
"flex-column",
|
|
||||||
"items-center",
|
|
||||||
"hover:bg-red-200",
|
|
||||||
"gap-1",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t.span(triptype.name)
|
|
||||||
t.span(
|
|
||||||
_class=cls(
|
|
||||||
"mdi", "mdi-delete", "text-sm"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.div(
|
|
||||||
_class=cls(
|
|
||||||
"flex",
|
|
||||||
"flex-row",
|
|
||||||
"flex-wrap",
|
|
||||||
"gap-2",
|
|
||||||
"justify-start",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
for triptype in triptypes:
|
|
||||||
if triptype not in trip.types:
|
|
||||||
with t.a(href=f"?type_add={triptype.id}"):
|
|
||||||
with t.li(
|
|
||||||
_class=cls(
|
|
||||||
"border",
|
|
||||||
"rounded-2xl",
|
|
||||||
"py-0.5",
|
|
||||||
"px-2",
|
|
||||||
"bg-gray-100",
|
|
||||||
"cursor-pointer",
|
|
||||||
"flex",
|
|
||||||
"flex-column",
|
|
||||||
"items-center",
|
|
||||||
"hover:bg-green-200",
|
|
||||||
"gap-1",
|
|
||||||
"opacity-60",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
t.span(triptype.name)
|
|
||||||
t.span(
|
|
||||||
_class=cls(
|
|
||||||
"mdi", "mdi-plus", "text-sm"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.tr():
|
|
||||||
t.td(f"Carried weight", _class=cls("border", "p-2"))
|
|
||||||
weight = sum(
|
|
||||||
[i.inventory_item.weight for i in trip.items if i.pick]
|
|
||||||
) / decimal.Decimal(1000)
|
|
||||||
t.td(f"{weight} kg", _class=cls("border", "p-2"))
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripComments:
|
|
||||||
def __init__(self, trip, baseurl):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Comments", _class=cls("text-xl", "mb-5"))
|
|
||||||
t.form(
|
|
||||||
id="edit-comment",
|
|
||||||
action=urllib.parse.urljoin(baseurl, f"edit/comment/submit/"),
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
# https://stackoverflow.com/a/48460773
|
|
||||||
t.textarea(
|
|
||||||
trip.comment or "",
|
|
||||||
name="comment",
|
|
||||||
form="edit-comment",
|
|
||||||
_class=cls("border", "w-full", "h-48"),
|
|
||||||
oninput='this.style.height = "";this.style.height = this.scrollHeight + 2 + "px"',
|
|
||||||
)
|
|
||||||
|
|
||||||
with t.button(
|
|
||||||
type="submit",
|
|
||||||
form=f"edit-comment",
|
|
||||||
_class=cls(
|
|
||||||
"mt-2",
|
|
||||||
"border",
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer",
|
|
||||||
"flex",
|
|
||||||
"flex-column",
|
|
||||||
"p-2",
|
|
||||||
"gap-2",
|
|
||||||
"items-center",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
t.span("Save")
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripActions:
|
|
||||||
def __init__(self, trip):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Actions", _class=cls("text-xl", "mb-5"))
|
|
||||||
|
|
||||||
with t.div(_class=cls("flex", "flex-column", "gap-2")):
|
|
||||||
if trip.state == TripState.Planning:
|
|
||||||
t.button("Finish planning", _class=cls("border", "p-2"))
|
|
||||||
if trip.state in (TripState.Planned, TripState.Active):
|
|
||||||
t.button("Start review", _class=cls("border", "p-2"))
|
|
||||||
if trip.state == TripState.Done:
|
|
||||||
t.button("Back to review", _class=cls("border", "p-2"))
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
class TripManager:
|
|
||||||
def __init__(self, trip, categories, active_category, edit, baseurl, triptypes):
|
|
||||||
with t.div(id="trips-manager", _class=cls("p-8")) as doc:
|
|
||||||
if edit == "name":
|
|
||||||
t.form(
|
|
||||||
id=f"edit-name",
|
|
||||||
action=urllib.parse.urljoin(baseurl, f"edit/name/submit/"),
|
|
||||||
target="_self",
|
|
||||||
method="post",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
)
|
|
||||||
with t.div(_class=cls("flex", "flex-row", "items-center", "gap-x-3")):
|
|
||||||
t._input(
|
|
||||||
_class=cls("bg-blue-200", "w-full", "h-full", "px-2", "text-2xl", "font-semibold"),
|
|
||||||
type="text",
|
|
||||||
id="item-edit-name",
|
|
||||||
form=f"edit-name",
|
|
||||||
name="name",
|
|
||||||
value=trip.name,
|
|
||||||
)
|
|
||||||
with t.a(href=baseurl):
|
|
||||||
with t.button(_class=cls(
|
|
||||||
"bg-red-200",
|
|
||||||
"hover:bg-red-400",
|
|
||||||
"cursor-pointer")):
|
|
||||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
|
||||||
with t.button(type="submit", form=f"edit-name", _class=cls(
|
|
||||||
"bg-green-200",
|
|
||||||
"hover:bg-green-400",
|
|
||||||
"cursor-pointer")):
|
|
||||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
|
||||||
else:
|
|
||||||
with t.div(_class=cls("flex", "flex-row", "items-center", "gap-x-3")):
|
|
||||||
t.h1(trip.name, _class=cls("text-2xl", "font-semibold"))
|
|
||||||
with t.span():
|
|
||||||
with t.a(
|
|
||||||
# data_hx_post=f"/item/{item.id}/edit",
|
|
||||||
href=f"?edit=name",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
):
|
|
||||||
with t.button():
|
|
||||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl", "opacity-50")),
|
|
||||||
|
|
||||||
with t.div(_class=cls("my-6")):
|
|
||||||
TripInfo(trip, edit, baseurl, triptypes).doc
|
|
||||||
|
|
||||||
with t.div(_class=cls("my-6")):
|
|
||||||
TripComments(trip, baseurl).doc
|
|
||||||
|
|
||||||
with t.div(_class=cls("my-6")):
|
|
||||||
TripActions(trip).doc
|
|
||||||
|
|
||||||
with t.div(_class=cls("my-6")):
|
|
||||||
TripItemManager(
|
|
||||||
trip, categories=categories, active_category=active_category
|
|
||||||
).doc
|
|
||||||
|
|
||||||
self.doc = doc
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from ..helpers import *
|
|
||||||
|
|
||||||
|
|
||||||
class TripRow(object):
|
|
||||||
def __init__(self, trip):
|
|
||||||
with t.tr(
|
|
||||||
_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-100", "h-full")
|
|
||||||
) as doc:
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
trip.name,
|
|
||||||
id="select-trip",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
t.p(str(trip.start_date)),
|
|
||||||
id="select-trip",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
t.p(str(trip.end_date)),
|
|
||||||
id="select-trip",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
t.p((trip.end_date - trip.start_date).days),
|
|
||||||
id="select-trip",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
today = datetime.datetime.now().date()
|
|
||||||
with t.td(_class=cls("border", "p-0", "m-0")):
|
|
||||||
t.a(
|
|
||||||
t.p(trip.state.name),
|
|
||||||
id="select-trip",
|
|
||||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
|
||||||
href=f"/trip/{trip.id}",
|
|
||||||
# data_hx_target="closest tr",
|
|
||||||
# data_hx_swap="outerHTML",
|
|
||||||
_class=cls("inline-block", "p-2", "m-0", "w-full"),
|
|
||||||
)
|
|
||||||
self.doc = doc
|
|
||||||
|
|
||||||
|
|
||||||
def TripTable(trips):
|
|
||||||
with t.div() as doc:
|
|
||||||
t.h1("Trips", _class=cls("text-2xl", "mb-5"))
|
|
||||||
with t.table(
|
|
||||||
id="trip-table",
|
|
||||||
_class=cls(
|
|
||||||
"table",
|
|
||||||
"table-auto",
|
|
||||||
"border-collapse",
|
|
||||||
"border-spacing-0",
|
|
||||||
"border",
|
|
||||||
"w-full",
|
|
||||||
),
|
|
||||||
):
|
|
||||||
with t.thead(_class=cls("bg-gray-200")):
|
|
||||||
t.tr(
|
|
||||||
t.th("Name", _class=cls("border", "p-2")),
|
|
||||||
t.th("From", _class=cls("border", "p-2")),
|
|
||||||
t.th("To", _class=cls("border", "p-2")),
|
|
||||||
t.th("Nights", _class=cls("border", "p-2")),
|
|
||||||
t.th("State", _class=cls("border", "p-2")),
|
|
||||||
_class="h-10",
|
|
||||||
)
|
|
||||||
with t.tbody() as b:
|
|
||||||
for trip in trips:
|
|
||||||
TripRow(trip).doc
|
|
||||||
|
|
||||||
return doc
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from .Base import Base
|
|
||||||
from .Home import Home
|
|
||||||
from .InventoryItemManager import InventoryItemManager
|
|
||||||
from .InventoryItemDetails import InventoryItemDetails
|
|
||||||
from .TripManager import TripManager
|
|
||||||
from .TripList import TripList
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
def cls(*args):
|
|
||||||
return " ".join([a for a in args if a is not None])
|
|
||||||
|
|
||||||
|
|
||||||
def jsbool(b):
|
|
||||||
return "true" if b else "false"
|
|
||||||
|
|
||||||
|
|
||||||
def alpinedata(d):
|
|
||||||
elements = []
|
|
||||||
for k, v in d.items():
|
|
||||||
elements.append(f"{k}: " + v)
|
|
||||||
|
|
||||||
return "{" + ",".join(elements) + "}"
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
document.body.addEventListener('htmx:responseError', function(evt) {
|
|
||||||
console.log(evt.detail);
|
|
||||||
});
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
from . import db
|
|
||||||
import enum
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemCategory(db.Model):
|
|
||||||
__tablename__ = "inventoryitemcategories"
|
|
||||||
id = db.Column(db.String(36), primary_key=True)
|
|
||||||
name = db.Column(db.Text, unique=True, nullable=False)
|
|
||||||
description = db.Column(db.Text)
|
|
||||||
items = db.relationship("InventoryItem", backref="category", lazy=True)
|
|
||||||
|
|
||||||
active = False
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItem(db.Model):
|
|
||||||
__tablename__ = "inventoryitems"
|
|
||||||
id = db.Column(db.String(36), primary_key=True)
|
|
||||||
name = db.Column(db.Text, unique=True, nullable=False)
|
|
||||||
description = db.Column(db.Text)
|
|
||||||
weight = db.Column(db.Integer, nullable=False)
|
|
||||||
category_id = db.Column(
|
|
||||||
db.String(36), db.ForeignKey("inventoryitemcategories.id"), nullable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
edit = False
|
|
||||||
|
|
||||||
|
|
||||||
class TripItems(db.Model):
|
|
||||||
__tablename__ = "tripitems"
|
|
||||||
item_id = db.Column(
|
|
||||||
db.String(36),
|
|
||||||
db.ForeignKey("inventoryitems.id"),
|
|
||||||
nullable=False,
|
|
||||||
primary_key=True,
|
|
||||||
)
|
|
||||||
trip_id = db.Column(
|
|
||||||
db.String(36), db.ForeignKey("trips.id"), nullable=False, primary_key=True
|
|
||||||
)
|
|
||||||
inventory_item = db.relationship("InventoryItem", lazy=True)
|
|
||||||
|
|
||||||
pick = db.Column(db.Boolean, nullable=False)
|
|
||||||
pack = db.Column(db.Boolean, nullable=False)
|
|
||||||
|
|
||||||
edit = False
|
|
||||||
|
|
||||||
|
|
||||||
class TripType(db.Model):
|
|
||||||
__tablename__ = "triptypes"
|
|
||||||
id = db.Column(db.String(36), primary_key=True)
|
|
||||||
name = db.Column(db.Text, unique=True, nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class TripToTripType(db.Model):
|
|
||||||
__tablename__ = "trips_to_triptypes"
|
|
||||||
trip_id = db.Column(
|
|
||||||
db.String(36), db.ForeignKey("trips.id"), nullable=False, primary_key=True
|
|
||||||
)
|
|
||||||
trip_type_id = db.Column(
|
|
||||||
db.String(36), db.ForeignKey("triptypes.id"), nullable=False, primary_key=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TripState(enum.Enum):
|
|
||||||
Planning = 1
|
|
||||||
Planned = 2
|
|
||||||
Active = 3
|
|
||||||
Review = 4
|
|
||||||
Done = 5
|
|
||||||
|
|
||||||
|
|
||||||
class Trip(db.Model):
|
|
||||||
__tablename__ = "trips"
|
|
||||||
id = db.Column(db.String(36), primary_key=True)
|
|
||||||
name = db.Column(db.Text, unique=True, nullable=False)
|
|
||||||
start_date = db.Column(db.Date, nullable=False)
|
|
||||||
end_date = db.Column(db.Date, nullable=False)
|
|
||||||
location = db.Column(db.Text, nullable=False)
|
|
||||||
temp_min = db.Column(db.Integer, nullable=False)
|
|
||||||
temp_max = db.Column(db.Integer, nullable=False)
|
|
||||||
|
|
||||||
comment = db.Column(db.Text, nullable=False)
|
|
||||||
|
|
||||||
types = db.relationship("TripType", secondary="trips_to_triptypes", lazy=True)
|
|
||||||
items = db.relationship("TripItems", lazy=True)
|
|
||||||
|
|
||||||
state = db.Column(db.Enum(TripState), nullable=False)
|
|
||||||
@@ -1,574 +0,0 @@
|
|||||||
import sqlalchemy
|
|
||||||
from . import app
|
|
||||||
from .models import *
|
|
||||||
from .helpers import *
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
import os
|
|
||||||
import urllib
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
import dominate
|
|
||||||
import dominate.tags as t
|
|
||||||
from dominate.util import raw
|
|
||||||
|
|
||||||
from .components import (
|
|
||||||
InventoryItemManager,
|
|
||||||
Base,
|
|
||||||
Home,
|
|
||||||
TripList,
|
|
||||||
TripManager,
|
|
||||||
InventoryItemDetails,
|
|
||||||
)
|
|
||||||
|
|
||||||
from flask import request, make_response
|
|
||||||
|
|
||||||
|
|
||||||
def get_categories():
|
|
||||||
return InventoryItemCategory.query.all()
|
|
||||||
|
|
||||||
|
|
||||||
def get_trips():
|
|
||||||
return Trip.query.all()
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_items():
|
|
||||||
return InventoryItem.query.all()
|
|
||||||
|
|
||||||
|
|
||||||
def get_triptypes():
|
|
||||||
return TripType.query.all()
|
|
||||||
|
|
||||||
|
|
||||||
def get_items(category):
|
|
||||||
return InventoryItem.query.filter_by(category_id=str(category.id))
|
|
||||||
|
|
||||||
|
|
||||||
def get_item(id):
|
|
||||||
return InventoryItem.query.filter_by(id=str(id)).first()
|
|
||||||
|
|
||||||
|
|
||||||
def get_trip(id):
|
|
||||||
return Trip.query.filter_by(id=str(id)).first()
|
|
||||||
|
|
||||||
|
|
||||||
def pick_item(trip_id, item_id):
|
|
||||||
item = TripItems.query.filter_by(item_id=str(item_id), trip_id=str(trip_id)).first()
|
|
||||||
item.pick = True
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def unpick_item(trip_id, item_id):
|
|
||||||
item = TripItems.query.filter_by(item_id=str(item_id), trip_id=str(trip_id)).first()
|
|
||||||
item.pick = False
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def pack_item(trip_id, item_id):
|
|
||||||
item = TripItems.query.filter_by(item_id=str(item_id), trip_id=str(trip_id)).first()
|
|
||||||
item.pack = True
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_item(trip_id, item_id):
|
|
||||||
item = TripItems.query.filter_by(item_id=str(item_id), trip_id=str(trip_id)).first()
|
|
||||||
item.pack = False
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def add_item(name, weight, category_id):
|
|
||||||
db.session.add(
|
|
||||||
InventoryItem(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
name=name,
|
|
||||||
description="",
|
|
||||||
weight=weight,
|
|
||||||
category_id=category_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
|
||||||
def root():
|
|
||||||
return make_response(Base(Home(), app.root_path).doc.render(), 200)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/")
|
|
||||||
def inventory():
|
|
||||||
categories = get_categories()
|
|
||||||
items = get_all_items()
|
|
||||||
|
|
||||||
args = request.args.to_dict()
|
|
||||||
|
|
||||||
error = False
|
|
||||||
if not is_htmx():
|
|
||||||
edit = request.args.get("edit")
|
|
||||||
if edit is not None:
|
|
||||||
match = [i for i in items if i.id == edit]
|
|
||||||
if match:
|
|
||||||
match[0].edit = True
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(
|
|
||||||
InventoryItemManager(categories, items, active_category=None),
|
|
||||||
app.root_path,
|
|
||||||
active_page="inventory",
|
|
||||||
).doc.render(),
|
|
||||||
200,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>/")
|
|
||||||
def inventory_item(id):
|
|
||||||
item = get_item(id)
|
|
||||||
|
|
||||||
args = request.args.to_dict()
|
|
||||||
edit = args.pop("edit", None)
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(
|
|
||||||
InventoryItemDetails(item, edit=edit, baseurl=f"/inventory/item/{id}/",), app.root_path, active_page="inventory"
|
|
||||||
).doc.render(),
|
|
||||||
200,
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.route(
|
|
||||||
"/inventory/item/<uuid:id>/edit/<string:attribute>/submit/",
|
|
||||||
methods=["POST"],
|
|
||||||
)
|
|
||||||
def edit_inventory_submit(id, attribute):
|
|
||||||
new_value = request.form[attribute]
|
|
||||||
|
|
||||||
if attribute in ("weight"):
|
|
||||||
new_value = int(new_value)
|
|
||||||
|
|
||||||
updates = InventoryItem.query.filter_by(id=str(id)).update({attribute: new_value})
|
|
||||||
db.session.commit()
|
|
||||||
if updates == 0:
|
|
||||||
# todo what to do without js?
|
|
||||||
return make_response("", 404)
|
|
||||||
|
|
||||||
redirect = request.path[: -(len(f"edit/{attribute}/submit/"))]
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = redirect
|
|
||||||
return r
|
|
||||||
|
|
||||||
@app.route("/trips/")
|
|
||||||
def trips():
|
|
||||||
trips = get_trips()
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(TripList(trips), app.root_path, active_page="trips").doc.render(), 200
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip/<uuid:id>/")
|
|
||||||
def trip(id):
|
|
||||||
|
|
||||||
args = request.args.to_dict()
|
|
||||||
|
|
||||||
item_to_pick = args.pop("item_pick", None)
|
|
||||||
if item_to_pick:
|
|
||||||
pick_item(id, item_to_pick)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_unpick = args.pop("item_unpick", None)
|
|
||||||
if item_to_unpick:
|
|
||||||
unpick_item(id, item_to_unpick)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_pack = args.pop("item_pack", None)
|
|
||||||
if item_to_pack:
|
|
||||||
pack_item(id, item_to_pack)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_unpack = args.pop("item_unpack", None)
|
|
||||||
if item_to_unpack:
|
|
||||||
unpack_item(id, item_to_unpack)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
type_to_add = args.pop("type_add", None)
|
|
||||||
if type_to_add:
|
|
||||||
newtype = TripToTripType(trip_id=str(id), trip_type_id=str(type_to_add))
|
|
||||||
db.session.add(newtype)
|
|
||||||
db.session.commit()
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
type_to_remove = args.pop("type_remove", None)
|
|
||||||
if type_to_remove:
|
|
||||||
newtype = TripToTripType.query.filter_by(
|
|
||||||
trip_id=str(id), trip_type_id=str(type_to_remove)
|
|
||||||
).delete()
|
|
||||||
db.session.commit()
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
trip = get_trip(id)
|
|
||||||
|
|
||||||
items = get_all_items()
|
|
||||||
|
|
||||||
categories = get_categories()
|
|
||||||
|
|
||||||
edit = args.pop("edit", None)
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
try:
|
|
||||||
db.session.add(
|
|
||||||
TripItems(trip_id=str(id), item_id=str(item.id), pick=False, pack=False)
|
|
||||||
)
|
|
||||||
db.session.commit()
|
|
||||||
except sqlalchemy.exc.IntegrityError:
|
|
||||||
db.session.rollback()
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(
|
|
||||||
TripManager(
|
|
||||||
trip,
|
|
||||||
categories=categories,
|
|
||||||
active_category=None,
|
|
||||||
edit=edit,
|
|
||||||
baseurl=f"/trip/{id}/",
|
|
||||||
triptypes=get_triptypes(),
|
|
||||||
),
|
|
||||||
app.root_path,
|
|
||||||
active_page="trips",
|
|
||||||
).doc.render(),
|
|
||||||
200,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route(
|
|
||||||
"/trip/<uuid:id>/category/<uuid:category_id>/edit/<string:attribute>/submit/",
|
|
||||||
methods=["POST"],
|
|
||||||
)
|
|
||||||
@app.route("/trip/<uuid:id>/edit/<string:attribute>/submit/", methods=["POST"])
|
|
||||||
def edit_trip_category_location_edit_submit(id, category_id=None, attribute=None):
|
|
||||||
new_value = request.form[attribute]
|
|
||||||
|
|
||||||
if attribute in ("start_date", "end_date"):
|
|
||||||
new_value = datetime.date.fromisoformat(new_value)
|
|
||||||
|
|
||||||
updates = Trip.query.filter_by(id=str(id)).update({attribute: new_value})
|
|
||||||
db.session.commit()
|
|
||||||
if updates == 0:
|
|
||||||
# todo what to do without js?
|
|
||||||
return make_response("", 404)
|
|
||||||
|
|
||||||
redirect = request.path[: -(len(f"edit/{attribute}/submit/"))]
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = redirect
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip/<uuid:id>/category/<uuid:category_id>/")
|
|
||||||
def trip_with_active_category(id, category_id):
|
|
||||||
trip = get_trip(id)
|
|
||||||
|
|
||||||
args = request.args.to_dict()
|
|
||||||
|
|
||||||
item_to_pick = args.pop("item_pick", None)
|
|
||||||
if item_to_pick:
|
|
||||||
pick_item(id, item_to_pick)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_unpick = args.pop("item_unpick", None)
|
|
||||||
if item_to_unpick:
|
|
||||||
unpick_item(id, item_to_unpick)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_pack = args.pop("item_pack", None)
|
|
||||||
if item_to_pack:
|
|
||||||
pack_item(id, item_to_pack)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
item_to_unpack = args.pop("item_unpack", None)
|
|
||||||
if item_to_unpack:
|
|
||||||
unpack_item(id, item_to_unpack)
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
type_to_add = args.pop("type_add", None)
|
|
||||||
if type_to_add:
|
|
||||||
newtype = TripToTripType(trip_id=str(id), trip_type_id=str(type_to_add))
|
|
||||||
db.session.add(newtype)
|
|
||||||
db.session.commit()
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
type_to_remove = args.pop("type_remove", None)
|
|
||||||
if type_to_remove:
|
|
||||||
newtype = TripToTripType.query.filter_by(
|
|
||||||
trip_id=str(id), trip_type_id=str(type_to_remove)
|
|
||||||
).delete()
|
|
||||||
db.session.commit()
|
|
||||||
r = make_response("", 303)
|
|
||||||
if args:
|
|
||||||
r.headers[
|
|
||||||
"Location"
|
|
||||||
] = f"/trip/{id}/category/{category_id}/?" + urllib.parse.urlencode(params)
|
|
||||||
else:
|
|
||||||
r.headers["Location"] = f"/trip/{id}/category/{category_id}/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
items = get_all_items()
|
|
||||||
|
|
||||||
categories = get_categories()
|
|
||||||
active_category = [c for c in categories if str(c.id) == str(category_id)][0]
|
|
||||||
active_category.active = True
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
try:
|
|
||||||
db.session.add(
|
|
||||||
TripItems(trip_id=str(id), item_id=str(item.id), pick=False, pack=False)
|
|
||||||
)
|
|
||||||
db.session.commit()
|
|
||||||
except sqlalchemy.exc.IntegrityError:
|
|
||||||
db.session.rollback()
|
|
||||||
|
|
||||||
edit = args.pop("edit", None)
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(
|
|
||||||
TripManager(
|
|
||||||
trip,
|
|
||||||
categories=categories,
|
|
||||||
active_category=active_category,
|
|
||||||
edit=edit,
|
|
||||||
baseurl=f"/trip/{id}/category/{category_id}/",
|
|
||||||
triptypes=get_triptypes(),
|
|
||||||
),
|
|
||||||
app.root_path,
|
|
||||||
active_page="trips",
|
|
||||||
).doc.render(),
|
|
||||||
200,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/category/<uuid:id>/")
|
|
||||||
def category(id):
|
|
||||||
categories = get_categories()
|
|
||||||
print(id)
|
|
||||||
active_category = [c for c in categories if str(c.id) == str(id)][0]
|
|
||||||
active_category.active = True
|
|
||||||
|
|
||||||
args = request.args.to_dict()
|
|
||||||
|
|
||||||
items = get_items(active_category)
|
|
||||||
error = False
|
|
||||||
if not is_htmx():
|
|
||||||
edit = request.args.get("edit")
|
|
||||||
if edit is not None:
|
|
||||||
match = [i for i in items if i.id == edit]
|
|
||||||
if match:
|
|
||||||
match[0].edit = True
|
|
||||||
|
|
||||||
return make_response(
|
|
||||||
Base(
|
|
||||||
InventoryItemManager(categories, items, active_category),
|
|
||||||
app.root_path,
|
|
||||||
active_page="inventory",
|
|
||||||
).doc.render(),
|
|
||||||
200,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_htmx():
|
|
||||||
return request.headers.get("HX-Request") is not None
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/", methods=["POST"])
|
|
||||||
def add_new_item():
|
|
||||||
name = request.form["name"]
|
|
||||||
weight = int(request.form["weight"])
|
|
||||||
category_id = request.form["category"]
|
|
||||||
|
|
||||||
add_item(name=name, weight=weight, category_id=category_id)
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = f"/inventory/category/{category_id}"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip/", methods=["POST"])
|
|
||||||
def add_new_trip():
|
|
||||||
name = request.form["name"]
|
|
||||||
start_date = datetime.date.fromisoformat(request.form["start-date"])
|
|
||||||
end_date = datetime.date.fromisoformat(request.form["end-date"])
|
|
||||||
|
|
||||||
newid = str(uuid.uuid4())
|
|
||||||
db.session.add(Trip(id=newid, name=name, start_date=start_date, end_date=end_date, location="Unknown", temp_min=0, temp_max=0, state=TripState.Planning))
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = f"/trip/{newid}" # TODO enable this
|
|
||||||
r.headers["Location"] = f"/trip/"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def validate_name(name):
|
|
||||||
error, errormsg = False, None
|
|
||||||
|
|
||||||
if len(name) == 0:
|
|
||||||
error = True
|
|
||||||
errormsg = f"Name cannot be empty"
|
|
||||||
elif name.isspace():
|
|
||||||
error = True
|
|
||||||
errormsg = f"Name cannot be only whitespace"
|
|
||||||
|
|
||||||
return error, errormsg
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>/edit/submit/", methods=["POST"])
|
|
||||||
def edit_item_submit(id):
|
|
||||||
name = request.form["name"]
|
|
||||||
weight = int(request.form["weight"])
|
|
||||||
|
|
||||||
item = InventoryItem.query.filter_by(id=str(id)).first()
|
|
||||||
if item is None:
|
|
||||||
# todo what to do without js?
|
|
||||||
return make_response("", 404)
|
|
||||||
|
|
||||||
item.name = name
|
|
||||||
item.weight = weight
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = f"/inventory/category/{item.category.id}"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>/pick/submit/", methods=["POST"])
|
|
||||||
def edit_item_pick(id):
|
|
||||||
print(request.form)
|
|
||||||
if "pick" in request.form:
|
|
||||||
pick = request.form["pick"] == "on"
|
|
||||||
else:
|
|
||||||
pick = False
|
|
||||||
print(pick)
|
|
||||||
|
|
||||||
item = InventoryItem.query.filter_by(id=str(id)).first()
|
|
||||||
if item is None:
|
|
||||||
# todo what to do without js?
|
|
||||||
return make_response("", 404)
|
|
||||||
|
|
||||||
item.picked = pick
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = f"/inventory/category/{item.category.id}"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>/pack/submit/", methods=["POST"])
|
|
||||||
def edit_item_pack(id):
|
|
||||||
print(request.form)
|
|
||||||
if "pack" in request.form:
|
|
||||||
pack = request.form["pack"] == "on"
|
|
||||||
else:
|
|
||||||
pack = False
|
|
||||||
print(pack)
|
|
||||||
|
|
||||||
item = InventoryItem.query.filter_by(id=str(id)).first()
|
|
||||||
if item is None:
|
|
||||||
# todo what to do without js?
|
|
||||||
return make_response("", 404)
|
|
||||||
|
|
||||||
item.pack = pack
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = f"/inventory/category/{item.category.id}"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>", methods=["DELETE"])
|
|
||||||
def delete_item(id):
|
|
||||||
deletions = InventoryItem.query.filter_by(id=str(id)).delete()
|
|
||||||
if deletions == 0:
|
|
||||||
return make_response("", 404)
|
|
||||||
else:
|
|
||||||
db.session.commit()
|
|
||||||
return make_response("", 200)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/inventory/item/<uuid:id>/delete", methods=["GET"])
|
|
||||||
def delete_item_get(id):
|
|
||||||
print(request.headers)
|
|
||||||
print(request.args)
|
|
||||||
print(f"deleting {id}")
|
|
||||||
deletions = InventoryItem.query.filter_by(id=str(id)).delete()
|
|
||||||
if deletions == 0:
|
|
||||||
return make_response("", 404)
|
|
||||||
else:
|
|
||||||
db.session.commit()
|
|
||||||
r = make_response("", 303)
|
|
||||||
r.headers["Location"] = request.headers["Referer"]
|
|
||||||
return r
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
alembic==1.8.1
|
|
||||||
click==8.1.3
|
|
||||||
dominate==2.6.0
|
|
||||||
Flask==2.1.2
|
|
||||||
Flask-Migrate==3.1.0
|
|
||||||
Flask-SQLAlchemy==2.5.1
|
|
||||||
greenlet==1.1.2
|
|
||||||
importlib-metadata==4.12.0
|
|
||||||
importlib-resources==5.9.0
|
|
||||||
itsdangerous==2.1.2
|
|
||||||
Jinja2==3.1.2
|
|
||||||
Mako==1.2.2
|
|
||||||
MarkupSafe==2.1.1
|
|
||||||
SQLAlchemy==1.4.39
|
|
||||||
Werkzeug==2.1.2
|
|
||||||
zipp==3.8.0
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
source ./venv/bin/activate
|
|
||||||
|
|
||||||
export FLASK_APP=packager
|
|
||||||
export FLASK_ENV=development
|
|
||||||
|
|
||||||
if (( $# == 0 )) ; then
|
|
||||||
python3 -m flask run --reload --host 0.0.0.0 --port 5000
|
|
||||||
else
|
|
||||||
python3 -m flask "${@}"
|
|
||||||
fi
|
|
||||||
1
python_flask/selenium/.gitignore
vendored
1
python_flask/selenium/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
/venv/
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
xtightvncviewer 127.0.0.1::5900 -passwd <(printf %s secret | vncpasswd -f)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
helium==3.0.8
|
|
||||||
selenium==3.141.0
|
|
||||||
urllib3==1.26.10
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
docker run \
|
|
||||||
--rm \
|
|
||||||
--publish 4444:4444 \
|
|
||||||
--env SE_OPTS="--session-timeout 36000" \
|
|
||||||
--shm-size="2g" \
|
|
||||||
--net=host \
|
|
||||||
--name docker-selenium \
|
|
||||||
selenium/standalone-firefox:4.3.0-20220706
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user