Selenium
This commit is contained in:
BIN
python_flask/packager.bundle
Normal file
BIN
python_flask/packager.bundle
Normal file
Binary file not shown.
@@ -7,7 +7,7 @@ from .helpers import *
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///./db.sqlite"
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{app.root_path}/../db.sqlite"
|
||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
|
||||
22
python_flask/packager/components/Home.py
Normal file
22
python_flask/packager/components/Home.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
|
||||
import dominate
|
||||
import dominate.tags as t
|
||||
from dominate.util import raw
|
||||
|
||||
|
||||
class Home:
|
||||
def __init__(self, element, root_path):
|
||||
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()))
|
||||
doc.add(element.doc)
|
||||
self.doc = doc
|
||||
@@ -17,7 +17,17 @@ def NewPackageList(name=None, description=None, error=False, errormsg=None):
|
||||
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-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"))
|
||||
@@ -41,6 +51,7 @@ def NewPackageList(name=None, description=None, error=False, errormsg=None):
|
||||
data_hx_target="#new-pkglist",
|
||||
data_hx_post="/list/name/validate",
|
||||
data_hx_swap="outerHTML",
|
||||
data_hx_trigger="changed",
|
||||
_class=cls(
|
||||
"block",
|
||||
"w-full",
|
||||
@@ -92,7 +103,7 @@ def NewPackageList(name=None, description=None, error=False, errormsg=None):
|
||||
type="submit",
|
||||
value="Add",
|
||||
**{
|
||||
"x-bind:class": 'submit_enabled ? "" : "cursor-not-allowed opacity-50"'
|
||||
"x-bind:class": 'submit_enabled ? "cursor-pointer" : "cursor-not-allowed opacity-50"'
|
||||
},
|
||||
_class=cls(
|
||||
"py-2",
|
||||
|
||||
@@ -12,13 +12,7 @@ class PackageListManager:
|
||||
self, pkglists, name=None, description=None, error=False, errormsg=None
|
||||
):
|
||||
assert not (error and not errormsg)
|
||||
with t.div(
|
||||
id="pkglist-manager",
|
||||
_class=cls("p-8", "max-w-xl"),
|
||||
**{
|
||||
"x-data": '{ submit_enabled: document.getElementById("listname").value.trim().length !== 0 }'
|
||||
},
|
||||
) as doc:
|
||||
with t.div(id="pkglist-manager", _class=cls("p-8", "max-w-xl")) as doc:
|
||||
PackageListTable(pkglists),
|
||||
NewPackageList(
|
||||
name=name, description=description, error=error, errormsg=errormsg
|
||||
|
||||
@@ -5,7 +5,102 @@ from dominate.util import raw
|
||||
from ..helpers import *
|
||||
|
||||
|
||||
class PackageListTableRow:
|
||||
class PackageListTableRowEdit:
|
||||
def __init__(self, pkglist):
|
||||
error, errormsg = pkglist.error, pkglist.errormsg
|
||||
assert not (error and not errormsg)
|
||||
with t.tr(
|
||||
_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-200"),
|
||||
id="pkglist-edit-row",
|
||||
**{
|
||||
"x-data": '{ edit_submit_enabled: document.getElementById("listedit-name").value.trim().length !== 0 }'
|
||||
},
|
||||
) as doc:
|
||||
with t.td(colspan=3, _class=cls("border-none", "bg-purple-100", "h-10")):
|
||||
with t.div():
|
||||
t.form(
|
||||
id="edit-pkglist",
|
||||
action=f"/list/{pkglist.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",
|
||||
)
|
||||
if error:
|
||||
t.p(errormsg, _class=cls("text-red-400", "text-sm"))
|
||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
||||
with t.div(
|
||||
_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="listedit-name",
|
||||
form="edit-pkglist",
|
||||
name="name",
|
||||
value=pkglist.name if error else pkglist.name,
|
||||
**{
|
||||
"x-on:input": "edit_submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
||||
},
|
||||
)
|
||||
with t.div(
|
||||
_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",
|
||||
name="description",
|
||||
form="edit-pkglist",
|
||||
value=pkglist.description,
|
||||
)
|
||||
with t.td(
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
id="edit-packagelist-abort",
|
||||
):
|
||||
with t.a(
|
||||
href="/",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit/cancel",
|
||||
data_hx_target="closest tr",
|
||||
data_hx_swap="outerHTML",
|
||||
):
|
||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
||||
with t.td(
|
||||
id="edit-packagelist-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-pkglist"):
|
||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
||||
self.doc = doc
|
||||
|
||||
|
||||
class PackageListTableRowNormal:
|
||||
def __init__(self, pkglist):
|
||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-200")) as doc:
|
||||
t.td(pkglist.name, _class=cls("border", "px-2")),
|
||||
@@ -14,6 +109,8 @@ class PackageListTableRow:
|
||||
t.span(_class=cls("mdi", "mdi-delete", "text-xl")),
|
||||
id="delete-packagelist",
|
||||
data_hx_delete=f"/list/{pkglist.id}",
|
||||
data_hx_target="closest tr",
|
||||
data_hx_swap="outerHTML",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
@@ -23,10 +120,7 @@ class PackageListTableRow:
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
||||
id="edit-packagelist",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit",
|
||||
with t.td(
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-blue-200",
|
||||
@@ -34,12 +128,20 @@ class PackageListTableRow:
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
)
|
||||
):
|
||||
with t.a(
|
||||
id="edit-packagelist",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit",
|
||||
href=f"/?edit={pkglist.id}",
|
||||
data_hx_target="closest tr",
|
||||
data_hx_swap="outerHTML",
|
||||
):
|
||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-arrow-right", "text-xl")),
|
||||
id="edit-packagelist",
|
||||
# data_hx_post=f"/list/{pkglist.id}/edit",
|
||||
# data_hx_post=f"/list/{pkglist.id}/show",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-green-200",
|
||||
@@ -52,9 +154,16 @@ class PackageListTableRow:
|
||||
self.doc = doc
|
||||
|
||||
|
||||
class PackageListTableRow:
|
||||
def __init__(self, pkglist):
|
||||
if pkglist.edit:
|
||||
self.doc = PackageListTableRowEdit(pkglist).doc
|
||||
else:
|
||||
self.doc = PackageListTableRowNormal(pkglist).doc
|
||||
|
||||
|
||||
def PackageListTable(pkglists):
|
||||
doc = t.div(id="packagelist-table")
|
||||
with doc:
|
||||
with t.div(id="packagelist-table") as doc:
|
||||
t.h1("Package Lists", _class=cls("text-2xl", "mb-5"))
|
||||
with t.table(
|
||||
id="packagelist-table",
|
||||
@@ -76,7 +185,7 @@ def PackageListTable(pkglists):
|
||||
t.th(_class=cls("border p-2")),
|
||||
_class="h-10",
|
||||
)
|
||||
with t.tbody(data_hx_target="closest tr", data_hx_swap="outerHTML"):
|
||||
with t.tbody() as b:
|
||||
for pkglist in pkglists:
|
||||
PackageListTableRow(pkglist).doc
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from .NewPackageList import NewPackageList
|
||||
from .PackageListTable import PackageListTable
|
||||
from .PackageListTable import (
|
||||
PackageListTable,
|
||||
PackageListTableRowEdit,
|
||||
PackageListTableRowNormal,
|
||||
PackageListTableRow,
|
||||
)
|
||||
from .PackageListManager import PackageListManager
|
||||
from .Home import Home
|
||||
|
||||
@@ -1,2 +1,14 @@
|
||||
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) + "}"
|
||||
|
||||
@@ -8,6 +8,10 @@ class PackageList(db.Model):
|
||||
description = db.Column(db.Text)
|
||||
items = db.relationship("PackageListItem", backref="packagelist", lazy=True)
|
||||
|
||||
edit = False
|
||||
error = False
|
||||
errormsg = None
|
||||
|
||||
|
||||
class PackageListItem(db.Model):
|
||||
__tablename__ = "packagelistitem"
|
||||
|
||||
@@ -10,7 +10,14 @@ import dominate
|
||||
import dominate.tags as t
|
||||
from dominate.util import raw
|
||||
|
||||
from .components import PackageListManager, NewPackageList, Home
|
||||
from .components import (
|
||||
PackageListManager,
|
||||
NewPackageList,
|
||||
Home,
|
||||
PackageListTableRowEdit,
|
||||
PackageListTableRowNormal,
|
||||
PackageListTableRow,
|
||||
)
|
||||
|
||||
from flask import request, make_response
|
||||
|
||||
@@ -45,8 +52,29 @@ def delete_packagelist(id):
|
||||
|
||||
@app.route("/")
|
||||
def root():
|
||||
packagelists = get_packagelists()
|
||||
error = False
|
||||
if not is_htmx():
|
||||
edit = request.args.get("edit")
|
||||
if edit is not None:
|
||||
match = [p for p in packagelists if p.id == edit]
|
||||
if match:
|
||||
match[0].edit = True
|
||||
error = request.args.get("error")
|
||||
if error and bool(int(error)):
|
||||
match[0].error = True
|
||||
errormsg = request.args.get("msg")
|
||||
if errormsg:
|
||||
match[0].errormsg = errormsg
|
||||
else:
|
||||
name = request.args.get("name")
|
||||
if name:
|
||||
match[0].errormsg = f"Invalid name: {name}"
|
||||
else:
|
||||
match[0].errormsg = f"Invalid name"
|
||||
|
||||
return make_response(
|
||||
Home(PackageListManager(get_packagelists()), app.root_path).doc.render(), 200
|
||||
Home(PackageListManager(packagelists), app.root_path).doc.render(), 200
|
||||
)
|
||||
|
||||
|
||||
@@ -56,7 +84,6 @@ def is_htmx():
|
||||
|
||||
@app.route("/list/", methods=["POST"])
|
||||
def add_new_list():
|
||||
print(f"headers: {request.headers}")
|
||||
name = request.form["name"]
|
||||
description = request.form["description"]
|
||||
|
||||
@@ -69,15 +96,13 @@ def add_new_list():
|
||||
|
||||
if is_htmx():
|
||||
return make_response(
|
||||
str(
|
||||
PackageListManager(
|
||||
get_packagelists(),
|
||||
name=name,
|
||||
description=description,
|
||||
error=error,
|
||||
errormsg=errormsg,
|
||||
)
|
||||
),
|
||||
).doc.render(),
|
||||
200 if error else 201,
|
||||
)
|
||||
else:
|
||||
@@ -116,309 +141,63 @@ def validate_list_name():
|
||||
|
||||
@app.route("/list/<uuid:id>/edit/cancel", methods=["POST"])
|
||||
def edit_list_cancel(id):
|
||||
print("cancelling" * 20)
|
||||
pkglist = PackageList.query.filter_by(id=str(id)).first()
|
||||
|
||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-200")) as doc:
|
||||
t.td(pkglist.name, _class=cls("border", "px-2")),
|
||||
t.td(str(pkglist.description), _class=cls("border", "px-2")),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-delete", "text-xl")),
|
||||
id="delete-packagelist",
|
||||
data_hx_delete=f"/list/{pkglist.id}",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
||||
id="edit-packagelist",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-blue-200",
|
||||
"hover:bg-blue-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
return make_response(doc.render(), 200)
|
||||
return make_response(PackageListTableRowNormal(pkglist).doc.render(), 200)
|
||||
|
||||
|
||||
@app.route("/list/<uuid:id>/edit/submit", methods=["POST"])
|
||||
@app.route("/list/<uuid:id>/edit/submit/", methods=["POST"])
|
||||
def edit_list_submit(id):
|
||||
name = request.form["name"]
|
||||
description = request.form["description"]
|
||||
if len(name) == 0:
|
||||
with t.tr(id="pkglist-edit-row") as doc:
|
||||
with t.td(colspan=3, _class=cls("border-none", "bg-purple-100", "h-10")):
|
||||
t.p("Name cannot be empty", _class=cls("text-red-400", "text-sm"))
|
||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
||||
with t.div(
|
||||
_class=cls(
|
||||
"box-border" "border",
|
||||
"border-2",
|
||||
"border-red-500",
|
||||
"bg-purple-100",
|
||||
"mr-1",
|
||||
)
|
||||
):
|
||||
with t.div(_class=cls("h-full")):
|
||||
t._input(
|
||||
_class=cls("bg-purple-100", "w-full", "h-full", "px-2"),
|
||||
type="text",
|
||||
name="name",
|
||||
value=name,
|
||||
)
|
||||
with t.div(
|
||||
_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",
|
||||
name="description",
|
||||
value=description,
|
||||
)
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
||||
id="edit-packagelist-abort",
|
||||
data_hx_post=f"/list/{id}/edit/cancel",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
||||
id="edit-packagelist-save",
|
||||
data_hx_post=f"/list/{id}/edit/submit",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
data_hx_include="closest tr",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-green-200",
|
||||
"hover:bg-green-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
return make_response(doc.render(), 200)
|
||||
error, errormsg = validate_name(name)
|
||||
|
||||
if error:
|
||||
if is_htmx():
|
||||
return make_response(
|
||||
PackageListTableRowEdit(error=True, errormsg=errormsg).doc.render(), 200
|
||||
)
|
||||
else:
|
||||
r = make_response("", 303)
|
||||
r.headers["Location"] = f"/?edit={id}&error=1&msg={errormsg}"
|
||||
return r
|
||||
|
||||
try:
|
||||
pkglist = PackageList.query.filter_by(id=str(id)).first()
|
||||
if pkglist is None:
|
||||
# todo what to do without js?
|
||||
return make_response("", 404)
|
||||
|
||||
pkglist.name = name
|
||||
pkglist.description = description
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
except sqlalchemy.exc.IntegrityError:
|
||||
with t.tr(id="pkglist-edit-row") as doc:
|
||||
with t.td(
|
||||
colspan=3, _class=cls("border-none", "bg-purple-100", "h-10")
|
||||
):
|
||||
t.p(
|
||||
f"Name {name} already exists",
|
||||
_class=cls("text-red-400", "text-sm"),
|
||||
)
|
||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
||||
with t.div(
|
||||
_class=cls(
|
||||
"box-border" "border",
|
||||
"border-2",
|
||||
"border-red-500",
|
||||
"bg-purple-100",
|
||||
"mr-1",
|
||||
)
|
||||
):
|
||||
with t.div(_class=cls("h-full")):
|
||||
t._input(
|
||||
_class=cls(
|
||||
"bg-purple-100", "w-full", "h-full", "px-2"
|
||||
),
|
||||
type="text",
|
||||
name="name",
|
||||
value=name,
|
||||
)
|
||||
with t.div(
|
||||
_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",
|
||||
name="description",
|
||||
value=description,
|
||||
)
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
||||
id="edit-packagelist-abort",
|
||||
data_hx_post=f"/list/{id}/edit/cancel",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
||||
id="edit-packagelist-save",
|
||||
data_hx_post=f"/list/{id}/edit/submit",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
data_hx_include="closest tr",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-green-200",
|
||||
"hover:bg-green-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
return make_response(doc.render(), 200)
|
||||
except:
|
||||
raise
|
||||
db.session.rollback()
|
||||
errormsg = f'Name "{name}" already exists'
|
||||
if is_htmx():
|
||||
pkglist.error = True
|
||||
pkglist.errormsg = errormsg
|
||||
return make_response(PackageListTableRowEdit(pkglist).doc.render(), 200)
|
||||
else:
|
||||
r = make_response("", 303)
|
||||
r.headers["Location"] = f"/?edit={id}&name={name}&error=1&msg={errormsg}"
|
||||
return r
|
||||
|
||||
with t.tr(_class=cls("h-10", "even:bg-gray-100", "hover:bg-purple-200")) as doc:
|
||||
t.td(pkglist.name, _class=cls("border", "px-2")),
|
||||
t.td(str(pkglist.description), _class=cls("border", "px-2")),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-delete", "text-xl")),
|
||||
id="delete-packagelist",
|
||||
data_hx_delete=f"/list/{pkglist.id}",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-pencil", "text-xl")),
|
||||
id="edit-packagelist",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-blue-200",
|
||||
"hover:bg-blue-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
return make_response(doc.render(), 200)
|
||||
|
||||
|
||||
def get_edit_list(pkglist):
|
||||
with t.tr(
|
||||
_class="h-10",
|
||||
id="pkglist-edit-row",
|
||||
**{
|
||||
"x-data": '{ edit_submit_enabled: document.getElementById("listedit-name").value.trim().length !== 0 }'
|
||||
},
|
||||
) as doc:
|
||||
with t.td(colspan=3, _class=cls("border-none", "bg-purple-100", "h-full")):
|
||||
with t.div(_class=cls("flex", "flex-row", "h-full")):
|
||||
with t.div(
|
||||
_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="listedit-name",
|
||||
name="name",
|
||||
value=pkglist.name,
|
||||
**{
|
||||
"x-on:input": "edit_submit_enabled = $event.srcElement.value.trim().length !== 0;"
|
||||
},
|
||||
)
|
||||
with t.div(
|
||||
_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",
|
||||
name="description",
|
||||
value=pkglist.description,
|
||||
)
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-cancel", "text-xl")),
|
||||
id="edit-packagelist-abort",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit/cancel",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
_class=cls(
|
||||
"border",
|
||||
"bg-red-200",
|
||||
"hover:bg-red-400",
|
||||
"cursor-pointer",
|
||||
"w-8",
|
||||
"text-center",
|
||||
),
|
||||
),
|
||||
t.td(
|
||||
t.span(_class=cls("mdi", "mdi-content-save", "text-xl")),
|
||||
id="edit-packagelist-save",
|
||||
data_hx_post=f"/list/{pkglist.id}/edit/submit",
|
||||
data_hx_target="#pkglist-edit-row",
|
||||
data_hx_swap="outerHTML",
|
||||
data_hx_include="closest #pkglist-edit-row",
|
||||
_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()",
|
||||
},
|
||||
),
|
||||
return doc
|
||||
if is_htmx():
|
||||
return make_response(PackageListTableRowNormal(pkglist).doc.render(), 200)
|
||||
else:
|
||||
r = make_response("", 303)
|
||||
r.headers["Location"] = "/"
|
||||
return r
|
||||
|
||||
|
||||
@app.route("/list/<uuid:id>/edit", methods=["POST"])
|
||||
def edit_list(id):
|
||||
pkglist = get_packagelist_by_id(id)
|
||||
|
||||
return make_response(get_edit_list(pkglist).render(), 200)
|
||||
out = PackageListTableRowEdit(pkglist).doc
|
||||
return make_response(out.render(), 200)
|
||||
|
||||
|
||||
@app.route("/list/<uuid:id>", methods=["DELETE"])
|
||||
|
||||
1
python_flask/selenium/.gitignore
vendored
Normal file
1
python_flask/selenium/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/venv/
|
||||
3
python_flask/selenium/connect.sh
Executable file
3
python_flask/selenium/connect.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
xtightvncviewer 127.0.0.1::5900 -passwd <(printf %s secret | vncpasswd -f)
|
||||
3
python_flask/selenium/requirements.txt
Normal file
3
python_flask/selenium/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
helium==3.0.8
|
||||
selenium==3.141.0
|
||||
urllib3==1.26.10
|
||||
10
python_flask/selenium/run-driver.sh
Executable file
10
python_flask/selenium/run-driver.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/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
|
||||
11
python_flask/selenium/setup.sh
Executable file
11
python_flask/selenium/setup.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -p pipefail
|
||||
|
||||
python3 -m venv ./venv
|
||||
source ./venv/bin/activate
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
sudo apt install tigervnc-common xtightvncviewer
|
||||
66
python_flask/selenium/test.py
Executable file
66
python_flask/selenium/test.py
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
|
||||
from helium import *
|
||||
import selenium
|
||||
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
opts = selenium.webdriver.firefox.options.Options()
|
||||
|
||||
profile = selenium.webdriver.FirefoxProfile()
|
||||
profile.set_preference("javascript.enabled", "false")
|
||||
profile.DEFAULT_PREFERENCES['frozen']['javascript.enabled'] = False
|
||||
opts.profile = profile
|
||||
|
||||
driver = selenium.webdriver.Remote(
|
||||
command_executor="http://localhost:4444/wd/hub",
|
||||
options=opts,
|
||||
)
|
||||
driver.implicitly_wait(0)
|
||||
Config.implicit_wait_secs = 1
|
||||
|
||||
try:
|
||||
helium.set_driver(driver)
|
||||
helium.go_to("http://localhost:5000")
|
||||
|
||||
assert driver.title == "Packager"
|
||||
|
||||
new_entry = Text("Add new package list")
|
||||
|
||||
lists_before = find_all(S("table > tbody > tr", below=Text("Package Lists")))
|
||||
|
||||
write("newlist", into=TextField(to_right_of="Name"))
|
||||
write("newlistdesc", into=TextField(to_right_of="Description"))
|
||||
click(Button("Add"))
|
||||
|
||||
lists_after = find_all(S("table > tbody > tr", below=Text("Package Lists")))
|
||||
|
||||
assert len(lists_before) == len(lists_after) - 1
|
||||
|
||||
nameidx = next(i for i,v in enumerate(find_all(S("table > thead > tr > th"))) if v.web_element.text == "Name")
|
||||
descidx = next(i for i,v in enumerate(find_all(S("table > thead > tr > th"))) if v.web_element.text == "Description")
|
||||
|
||||
new_entry = lists_after[-1]
|
||||
|
||||
cells = new_entry.web_element.find_elements_by_tag_name("td")
|
||||
|
||||
assert cells[nameidx].text == "newlist"
|
||||
assert cells[descidx].text == "newlistdesc"
|
||||
|
||||
lists_before = lists_after
|
||||
|
||||
deletebtn = new_entry.web_element.find_element_by_class_name("mdi-delete")
|
||||
|
||||
click(deletebtn)
|
||||
|
||||
lists_after = find_all(S("table > tbody > tr", below=Text("Package Lists")))
|
||||
|
||||
assert len(lists_before) - 1 == len(lists_after)
|
||||
|
||||
import code; code.interact(local=locals())
|
||||
time.sleep(5)
|
||||
finally:
|
||||
driver.quit()
|
||||
Reference in New Issue
Block a user