Add edit page, dialog based item page. Consider switching to popups.
This commit is contained in:
parent
2a8de79adb
commit
27169ff8a0
@ -1,12 +1,8 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.13-slim
|
||||||
|
|
||||||
# Get runtime dependencies
|
|
||||||
# glx for OpenCV, ghostscript for datasheet PDF rendering, zbar for barcode scanning, git for cloning repos
|
|
||||||
#RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript libzbar0 git && apt-get clean && rm -rf /var/lib/apt/lists
|
|
||||||
COPY requirements.txt ./
|
COPY requirements.txt ./
|
||||||
#COPY config-server.yml config.yml
|
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
COPY *.py *.txt *.toml ./
|
COPY *.py *.txt *.toml ./
|
||||||
COPY inventory ./inventory
|
COPY inventory ./inventory
|
||||||
CMD ["rio", "run", "--release", "--public", "--port", "8000"]
|
CMD ["rio", "run", "--release", "--public", "--port", "8000"]
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
100
db_classes.py
100
db_classes.py
@ -24,7 +24,7 @@ class office(Model):
|
|||||||
|
|
||||||
class location(Model):
|
class location(Model):
|
||||||
name = CharField()
|
name = CharField()
|
||||||
locationid = AutoField()
|
locationid = CharField(unique=True, primary_key=True)
|
||||||
description = CharField(null=True)
|
description = CharField(null=True)
|
||||||
|
|
||||||
parent = ForeignKeyField('self', null=True, backref="sublocations")
|
parent = ForeignKeyField('self', null=True, backref="sublocations")
|
||||||
@ -42,6 +42,7 @@ class item(Model):
|
|||||||
description = CharField(null=True)
|
description = CharField(null=True)
|
||||||
serial = CharField(null=True)
|
serial = CharField(null=True)
|
||||||
checkout = BooleanField(default=False)
|
checkout = BooleanField(default=False)
|
||||||
|
checkout_loc = ForeignKeyField(location, backref="items_checkedout_here", null=True)
|
||||||
checkout_user = ForeignKeyField(user, backref="items_held", null=True)
|
checkout_user = ForeignKeyField(user, backref="items_held", null=True)
|
||||||
checkout_start = DateTimeField(null=True)
|
checkout_start = DateTimeField(null=True)
|
||||||
checkout_end = DateTimeField(null=True)
|
checkout_end = DateTimeField(null=True)
|
||||||
@ -70,7 +71,13 @@ class component(Model):
|
|||||||
|
|
||||||
def init():
|
def init():
|
||||||
print("Connecting to database...")
|
print("Connecting to database...")
|
||||||
db.connect()
|
import time
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
db.connect()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
time.sleep(1)
|
||||||
print("Checking & creating tables...")
|
print("Checking & creating tables...")
|
||||||
db.create_tables([location, office, item, component, user])
|
db.create_tables([location, office, item, component, user])
|
||||||
print("Database initialized.")
|
print("Database initialized.")
|
||||||
@ -81,6 +88,10 @@ def init():
|
|||||||
#print(add)
|
#print(add)
|
||||||
#print(type(add))
|
#print(type(add))
|
||||||
for itm in add:
|
for itm in add:
|
||||||
|
try:
|
||||||
|
itm["location"] = item.select().where(item.barcode==itm["barcode"])[0].loc.name
|
||||||
|
except:
|
||||||
|
pass
|
||||||
print(itm)
|
print(itm)
|
||||||
#print(type(itm))
|
#print(type(itm))
|
||||||
search.add_document(itm)
|
search.add_document(itm)
|
||||||
@ -115,17 +126,65 @@ def search_item(query, filters: dict={}):
|
|||||||
def find_item(barcode):
|
def find_item(barcode):
|
||||||
return search.get_barcode(barcode)
|
return search.get_barcode(barcode)
|
||||||
|
|
||||||
def create_item(fullname, serial, officename, barcode, location=None, description=None, manufacturer=None, mac=None, fwver=None):
|
def find_item_location(barcode):
|
||||||
|
try:
|
||||||
|
return item.select().where(item.barcode==barcode).loc
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def create_item(fullname, serial, officename, barcode, locationid=None, description=None, manufacturer=None, mac=None, fwver=None):
|
||||||
try:
|
try:
|
||||||
off = office(name=officename)
|
off = office(name=officename)
|
||||||
off.save(force_insert=True)
|
off.save(force_insert=True)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
|
loc = get_location_id(locationid)
|
||||||
|
if loc == False:
|
||||||
|
loc = None
|
||||||
|
else:
|
||||||
|
print("Found location: " + loc.name)
|
||||||
off = office.select().where(office.name == officename)[0]
|
off = office.select().where(office.name == officename)[0]
|
||||||
itm = item(office=off, barcode=barcode, fullname=fullname, description=description, loc=location, serial=serial, mac=mac, fwver=fwver, manufacturer=manufacturer)
|
itm = item(office=off, barcode=barcode, fullname=fullname, description=description, loc=loc, serial=serial, mac=mac, fwver=fwver, manufacturer=manufacturer)
|
||||||
itm.save(force_insert=True)
|
itm.save(force_insert=True)
|
||||||
search.add_document(item.select().where(item.barcode==barcode).dicts()[0])
|
itmdict= item.select().where(item.barcode==barcode).dicts()[0]
|
||||||
|
try:
|
||||||
|
itmdict["location"] = loc.name
|
||||||
|
#print(locationid)
|
||||||
|
#print(itmdict["location"])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
search.add_document(itmdict)
|
||||||
|
print("item: " + itm.fullname)
|
||||||
|
return itm
|
||||||
|
except IntegrityError:
|
||||||
|
print("Duplicate item " + fullname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def update_item(fullname, serial, officename, barcode, locationid=None, description=None, manufacturer=None, mac=None, fwver=None):
|
||||||
|
try:
|
||||||
|
off = office(name=officename)
|
||||||
|
off.save(force_insert=True)
|
||||||
|
except IntegrityError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
loc = get_location_id(locationid)
|
||||||
|
if loc == False:
|
||||||
|
loc = None
|
||||||
|
else:
|
||||||
|
print("Found location: " + loc.name)
|
||||||
|
off = office.select().where(office.name == officename)[0]
|
||||||
|
itm = item(office=off, barcode=barcode, fullname=fullname, description=description, loc=loc, serial=serial, mac=mac, fwver=fwver, manufacturer=manufacturer)
|
||||||
|
itm.save()
|
||||||
|
itmdict= item.select().where(item.barcode==barcode).dicts()[0]
|
||||||
|
try:
|
||||||
|
itmdict["location"] = loc.name
|
||||||
|
#print(locationid)
|
||||||
|
#print(itmdict["location"])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
search.add_document(itmdict)
|
||||||
print("item: " + itm.fullname)
|
print("item: " + itm.fullname)
|
||||||
return itm
|
return itm
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
@ -196,7 +255,7 @@ def checkout(user, barcode, loc=None):
|
|||||||
if itm:
|
if itm:
|
||||||
itm.checkout = True
|
itm.checkout = True
|
||||||
itm.checkout_user = user
|
itm.checkout_user = user
|
||||||
itm.loc = loc
|
itm.checkout_loc = loc
|
||||||
itm.save()
|
itm.save()
|
||||||
return itm
|
return itm
|
||||||
else:
|
else:
|
||||||
@ -207,19 +266,21 @@ def checkin(user, barcode, loc=None):
|
|||||||
if itm:
|
if itm:
|
||||||
itm.checkout = False
|
itm.checkout = False
|
||||||
itm.last_user = user
|
itm.last_user = user
|
||||||
itm.loc = loc
|
if loc is not None:
|
||||||
|
itm.loc = loc
|
||||||
itm.save()
|
itm.save()
|
||||||
return itm
|
return itm
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def create_location(name, parent=None):
|
def create_location(name, barcode, parent=None, description=None):
|
||||||
if parent is not None:
|
try:
|
||||||
loc = location(name=name, parent=parent)
|
loc = location(name=name, locationid=barcode, parent=parent, description=description)
|
||||||
loc.save()
|
loc.save(force_insert=True)
|
||||||
|
print(loc.name, loc.locationid)
|
||||||
return loc
|
return loc
|
||||||
else:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _find_parent(loc, parent):
|
def _find_parent(loc, parent):
|
||||||
@ -247,6 +308,21 @@ def get_location(name, parent=None):
|
|||||||
return False
|
return False
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_location_id(barcode):
|
||||||
|
try:
|
||||||
|
print("str" + barcode + "str")
|
||||||
|
if len(barcode) > 0:
|
||||||
|
query = location.select()
|
||||||
|
for loc in query:
|
||||||
|
print(loc.name, loc.locationid)
|
||||||
|
if loc.locationid == barcode:
|
||||||
|
return loc
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
def get_user(name):
|
def get_user(name):
|
||||||
query = user.select().where(user.username == name)
|
query = user.select().where(user.username == name)
|
||||||
|
@ -35,26 +35,31 @@ app = rio.App(
|
|||||||
comps.Settings(),
|
comps.Settings(),
|
||||||
],
|
],
|
||||||
pages=[
|
pages=[
|
||||||
rio.Page(
|
rio.ComponentPage(
|
||||||
name="Home",
|
name="Home",
|
||||||
page_url='',
|
url_segment='',
|
||||||
build=pages.BrowsePage,
|
build=pages.BrowsePage,
|
||||||
),
|
),
|
||||||
|
|
||||||
rio.Page(
|
rio.ComponentPage(
|
||||||
name="AboutPage",
|
name="SettingsPage",
|
||||||
page_url='about-page',
|
url_segment='settings-page',
|
||||||
build=pages.AboutPage,
|
build=pages.SettingsPage,
|
||||||
),
|
),
|
||||||
|
|
||||||
rio.Page(
|
rio.ComponentPage(
|
||||||
name="AddPage",
|
name="AddPage",
|
||||||
page_url='add',
|
url_segment='add',
|
||||||
build=pages.AddPage,
|
build=pages.AddPage,
|
||||||
),
|
),
|
||||||
rio.Page(
|
rio.ComponentPage(
|
||||||
|
name="AddLocationPage",
|
||||||
|
url_segment='addlocation',
|
||||||
|
build=pages.AddLocationPage,
|
||||||
|
),
|
||||||
|
rio.ComponentPage(
|
||||||
name="ItemPage",
|
name="ItemPage",
|
||||||
page_url='item',
|
url_segment='item',
|
||||||
build=pages.ItemPage,
|
build=pages.ItemPage,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -16,7 +16,6 @@ class Footer(rio.Component):
|
|||||||
def build(self) -> rio.Component:
|
def build(self) -> rio.Component:
|
||||||
return rio.Card(
|
return rio.Card(
|
||||||
content=rio.Column(
|
content=rio.Column(
|
||||||
rio.Icon("rio/logo:fill", width=5, height=5),
|
|
||||||
rio.Text("Buzzwordz Inc."),
|
rio.Text("Buzzwordz Inc."),
|
||||||
rio.Text(
|
rio.Text(
|
||||||
"Hyper Dyper Website",
|
"Hyper Dyper Website",
|
||||||
|
@ -60,7 +60,7 @@ class Navbar(rio.Component):
|
|||||||
# you've passed the app during creation. Since multiple pages can be
|
# you've passed the app during creation. Since multiple pages can be
|
||||||
# active at a time (e.g. /foo/bar/baz), this is a list.
|
# active at a time (e.g. /foo/bar/baz), this is a list.
|
||||||
active_page = self.session.active_page_instances[0]
|
active_page = self.session.active_page_instances[0]
|
||||||
active_page_url_segment = active_page.page_url
|
active_page_url_segment = active_page.url_segment
|
||||||
|
|
||||||
# The navbar should appear above all other components. This is easily
|
# The navbar should appear above all other components. This is easily
|
||||||
# done by using a `rio.Overlay` component.
|
# done by using a `rio.Overlay` component.
|
||||||
@ -80,7 +80,7 @@ class Navbar(rio.Component):
|
|||||||
style=(
|
style=(
|
||||||
"major"
|
"major"
|
||||||
if active_page_url_segment == ""
|
if active_page_url_segment == ""
|
||||||
else "plain"
|
else "plain-text"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"/",
|
"/",
|
||||||
@ -121,23 +121,35 @@ class Navbar(rio.Component):
|
|||||||
style=(
|
style=(
|
||||||
"major"
|
"major"
|
||||||
if active_page_url_segment == "add"
|
if active_page_url_segment == "add"
|
||||||
else "plain"
|
else "plain-text"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"/add",
|
"/add",
|
||||||
),
|
),
|
||||||
|
rio.Link(
|
||||||
|
rio.Button(
|
||||||
|
"Locations",
|
||||||
|
icon="material/news",
|
||||||
|
style=(
|
||||||
|
"major"
|
||||||
|
if active_page_url_segment == "addlocation"
|
||||||
|
else "plain-text"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"/addlocation",
|
||||||
|
),
|
||||||
# Same game, different button
|
# Same game, different button
|
||||||
rio.Link(
|
rio.Link(
|
||||||
rio.Button(
|
rio.Button(
|
||||||
"About",
|
"Settings",
|
||||||
icon="material/info",
|
icon="material/info",
|
||||||
style=(
|
style=(
|
||||||
"major"
|
"major"
|
||||||
if active_page_url_segment == "about-page"
|
if active_page_url_segment == "settings-page"
|
||||||
else "plain"
|
else "plain-text"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"/about-page",
|
"/settings-page",
|
||||||
),
|
),
|
||||||
spacing=1,
|
spacing=1,
|
||||||
margin=1,
|
margin=1,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from .root_page import RootPage
|
from .root_page import RootPage
|
||||||
from .about_page import AboutPage
|
from .settings_page import SettingsPage
|
||||||
from .add_page import AddPage
|
from .add_page import AddPage
|
||||||
|
from .add_location import AddLocationPage
|
||||||
from .browse_page import BrowsePage
|
from .browse_page import BrowsePage
|
||||||
from .login_page import LoginPage
|
from .login_page import LoginPage
|
||||||
from .item_page import ItemPage
|
from .item_page import ItemPage
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dataclasses import KW_ONLY, field
|
|
||||||
from typing import * # type: ignore
|
|
||||||
|
|
||||||
import rio
|
|
||||||
|
|
||||||
from .. import components as comps
|
|
||||||
|
|
||||||
class AboutPage(rio.Component):
|
|
||||||
"""
|
|
||||||
A sample page, which displays a humorous description of the company.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def build(self) -> rio.Component:
|
|
||||||
return rio.Markdown(
|
|
||||||
"""
|
|
||||||
# About Us
|
|
||||||
|
|
||||||
Welcome to Buzzwordz Inc.! Unleashing Synergistic Paradigms for Unprecedented
|
|
||||||
Excellence since the day after yesterday.
|
|
||||||
|
|
||||||
## About Our Company
|
|
||||||
|
|
||||||
At buzzwordz, we are all talk and no action. Our mission is to be the vanguards
|
|
||||||
of industry-leading solutions, leveraging bleeding-edge technologies to catapult
|
|
||||||
your business into the stratosphere of success. Our unparalleled team of ninjas,
|
|
||||||
gurus, and rockstars is dedicated to disrupting the status quo and actualizing
|
|
||||||
your wildest business dreams. We live, breathe, and eat operational excellence
|
|
||||||
and groundbreaking innovation.
|
|
||||||
|
|
||||||
## Synergistic Consulting
|
|
||||||
|
|
||||||
Unlock your business's quantum potential with our bespoke, game-changing
|
|
||||||
strategies. Our consulting services synergize cross-functional paradigms to
|
|
||||||
create a holistic ecosystem of perpetual growth and exponential ROI. Did I
|
|
||||||
mention paradigm-shifts? We've got those too.
|
|
||||||
|
|
||||||
## Agile Hyper-Development
|
|
||||||
|
|
||||||
We turn moonshot ideas into reality with our agile, ninja-level development
|
|
||||||
techniques. Our team of coding wizards crafts robust, scalable, and future-proof
|
|
||||||
solutions that redefine industry standards. 24/7 Proactive Hyper-Support
|
|
||||||
|
|
||||||
Experience next-gen support that anticipates your needs before you do. Our
|
|
||||||
omnipresent customer happiness engineers ensure seamless integration,
|
|
||||||
frictionless operation, and infinite satisfaction, day and night.
|
|
||||||
|
|
||||||
Embark on a journey of transformational growth and stratospheric success. Don't
|
|
||||||
delay, give us your money today.
|
|
||||||
|
|
||||||
Phone: (123) 456-7890
|
|
||||||
|
|
||||||
Email: info@yourwebsite.com
|
|
||||||
|
|
||||||
Address: 123 Main Street, City, Country
|
|
||||||
""",
|
|
||||||
width=60,
|
|
||||||
margin_bottom=4,
|
|
||||||
align_x=0.5,
|
|
||||||
align_y=0,
|
|
||||||
)
|
|
||||||
|
|
118
inventory/pages/add_location.py
Normal file
118
inventory/pages/add_location.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import KW_ONLY, field
|
||||||
|
from typing import * # type: ignore
|
||||||
|
|
||||||
|
import rio
|
||||||
|
import datetime
|
||||||
|
from mac_vendor_lookup import AsyncMacLookup
|
||||||
|
|
||||||
|
from db_classes import *
|
||||||
|
from .. import components as comps
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
class AddLocationPage(rio.Component):
|
||||||
|
code: str = ""
|
||||||
|
popup_message: str = ""
|
||||||
|
popup_show: bool = False
|
||||||
|
popup_color: str = 'warning'
|
||||||
|
description: str = ""
|
||||||
|
name: str = ""
|
||||||
|
parent_code: str = ""
|
||||||
|
parent: str = ""
|
||||||
|
|
||||||
|
@rio.event.periodic(1)
|
||||||
|
def set_office_init(self):
|
||||||
|
self.office = self.session[comps.Settings].office
|
||||||
|
#print("Populated:", self.office)
|
||||||
|
|
||||||
|
async def _update_location(self, event: rio.TextInputChangeEvent):
|
||||||
|
print("Checking " + self.parent)
|
||||||
|
if get_location_id(self.parent) != False:
|
||||||
|
self.parent_code = self.parent
|
||||||
|
print("Found location " + get_location_id(self.parent).name)
|
||||||
|
self.parent = get_location_id(self.parent).name
|
||||||
|
|
||||||
|
async def add_part(self):
|
||||||
|
if self.code == "":
|
||||||
|
# FAIL
|
||||||
|
self.popup_message = "\n Missing barcode! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'danger'
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
self.popup_show = False
|
||||||
|
else:
|
||||||
|
# OK, add part
|
||||||
|
if get_location_id(self.parent_code) != False:
|
||||||
|
self.parent = get_location_id(self.parent_code)
|
||||||
|
else:
|
||||||
|
self.parent = None
|
||||||
|
if create_location(name=self.name, barcode=self.code, parent=self.parent, description=self.description) == False:
|
||||||
|
self.popup_message = "\n Duplicate barcode! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'warning'
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
|
else:
|
||||||
|
self.popup_message = "\n Part added! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'success'
|
||||||
|
self.name: str = ""
|
||||||
|
self.code: str = ""
|
||||||
|
self.description: str = ""
|
||||||
|
self.parent_code: str = ""
|
||||||
|
self.parent: str = ""
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
|
|
||||||
|
|
||||||
|
async def _add_part_enter(self, event: rio.TextInputConfirmEvent):
|
||||||
|
await self.add_part()
|
||||||
|
|
||||||
|
async def _add_part_button(self):
|
||||||
|
await self.add_part()
|
||||||
|
|
||||||
|
def build(self) -> rio.Component:
|
||||||
|
return rio.Column(
|
||||||
|
rio.Popup(
|
||||||
|
anchor=rio.Text(
|
||||||
|
text="Add a part below:",
|
||||||
|
style='heading1',
|
||||||
|
align_x = 0.5
|
||||||
|
),
|
||||||
|
color=self.bind().popup_color,
|
||||||
|
is_open=self.bind().popup_show,
|
||||||
|
content=rio.Text(
|
||||||
|
text=self.bind().popup_message,
|
||||||
|
),
|
||||||
|
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Barcode",
|
||||||
|
text=self.bind().code
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Parent Location (optional)",
|
||||||
|
text=self.bind().parent,
|
||||||
|
on_change=self._update_location
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Location Name",
|
||||||
|
text=self.bind().name
|
||||||
|
),
|
||||||
|
rio.MultiLineTextInput(
|
||||||
|
label="Description (optional)",
|
||||||
|
text=self.bind().description
|
||||||
|
),
|
||||||
|
rio.Button(
|
||||||
|
content="Add",
|
||||||
|
on_press=self._add_part_button
|
||||||
|
),
|
||||||
|
|
||||||
|
spacing=2,
|
||||||
|
min_width=60,
|
||||||
|
margin_bottom=4,
|
||||||
|
align_x=0.5,
|
||||||
|
align_y=0,
|
||||||
|
)
|
||||||
|
|
@ -10,7 +10,14 @@ from mac_vendor_lookup import AsyncMacLookup
|
|||||||
from db_classes import *
|
from db_classes import *
|
||||||
from .. import components as comps
|
from .. import components as comps
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
class AddPage(rio.Component):
|
class AddPage(rio.Component):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A set of fields for adding/editing items.
|
||||||
|
"""
|
||||||
|
|
||||||
partnum: str = ""
|
partnum: str = ""
|
||||||
mac: str = ""
|
mac: str = ""
|
||||||
serial: str = ""
|
serial: str = ""
|
||||||
@ -27,6 +34,9 @@ class AddPage(rio.Component):
|
|||||||
manu: str = ""
|
manu: str = ""
|
||||||
manufield: str = ""
|
manufield: str = ""
|
||||||
office: str = ""
|
office: str = ""
|
||||||
|
description: str = ""
|
||||||
|
location: str = ""
|
||||||
|
location_code: str = ""
|
||||||
|
|
||||||
@rio.event.periodic(1)
|
@rio.event.periodic(1)
|
||||||
def set_office_init(self):
|
def set_office_init(self):
|
||||||
@ -60,12 +70,16 @@ class AddPage(rio.Component):
|
|||||||
self.popup_message = "\n Missing barcode! \n\n"
|
self.popup_message = "\n Missing barcode! \n\n"
|
||||||
self.popup_show = True
|
self.popup_show = True
|
||||||
self.popup_color = 'danger'
|
self.popup_color = 'danger'
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
else:
|
else:
|
||||||
# OK, add part
|
# OK, add part
|
||||||
if create_item(self.partnum, self.serial, self.office, self.code, location=None, description=None, manufacturer=self.manu, mac=self.mac, fwver=self.fwver) == False:
|
if create_item(self.partnum, self.serial, self.office, self.code, locationid=self.location_code, description=self.description, manufacturer=self.manu, mac=self.mac, fwver=self.fwver) == False:
|
||||||
self.popup_message = "\n Duplicate barcode! \n\n"
|
self.popup_message = "\n Duplicate barcode! \n\n"
|
||||||
self.popup_show = True
|
self.popup_show = True
|
||||||
self.popup_color = 'warning'
|
self.popup_color = 'warning'
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
else:
|
else:
|
||||||
self.popup_message = "\n Part added! \n\n"
|
self.popup_message = "\n Part added! \n\n"
|
||||||
self.popup_show = True
|
self.popup_show = True
|
||||||
@ -79,6 +93,11 @@ class AddPage(rio.Component):
|
|||||||
self.macvendor: str = ""
|
self.macvendor: str = ""
|
||||||
self.manu: str = ""
|
self.manu: str = ""
|
||||||
self.manufield: str = ""
|
self.manufield: str = ""
|
||||||
|
self.description: str = ""
|
||||||
|
self.location: str = ""
|
||||||
|
self.location_code: str = ""
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
|
|
||||||
|
|
||||||
async def _add_part_enter(self, event: rio.TextInputConfirmEvent):
|
async def _add_part_enter(self, event: rio.TextInputConfirmEvent):
|
||||||
@ -107,8 +126,16 @@ class AddPage(rio.Component):
|
|||||||
async def _update_mac(self, event: rio.TextInputChangeEvent):
|
async def _update_mac(self, event: rio.TextInputChangeEvent):
|
||||||
await self.check_mac(event.text)
|
await self.check_mac(event.text)
|
||||||
|
|
||||||
|
async def _update_location(self, event: rio.TextInputChangeEvent):
|
||||||
|
print("Checking " + self.location)
|
||||||
|
if get_location_id(self.location) != False:
|
||||||
|
self.location_code = self.location
|
||||||
|
print("Found location " + get_location_id(self.location).name)
|
||||||
|
self.location = get_location_id(self.location).name
|
||||||
|
|
||||||
|
|
||||||
def _update_partnum(self, event: rio.TextInputChangeEvent):
|
def _update_partnum(self, event: rio.TextInputChangeEvent):
|
||||||
def __find_hm_header(txt):
|
def __find_hm_header_static(txt):
|
||||||
searchlist = ["RSPS", "RSPE", "RSP", "RSB", "LRS", "RS", "OS", "RED", "MSP", "MSM", "MS", "MM", "EESX", "EES", "OZD", "OBR"]
|
searchlist = ["RSPS", "RSPE", "RSP", "RSB", "LRS", "RS", "OS", "RED", "MSP", "MSM", "MS", "MM", "EESX", "EES", "OZD", "OBR"]
|
||||||
for header in searchlist:
|
for header in searchlist:
|
||||||
if txt.find(header) >= 0:
|
if txt.find(header) >= 0:
|
||||||
@ -129,6 +156,8 @@ class AddPage(rio.Component):
|
|||||||
|
|
||||||
if dash and acount <= 5 and ncount <= 5:
|
if dash and acount <= 5 and ncount <= 5:
|
||||||
return acount+ncount
|
return acount+ncount
|
||||||
|
elif dash and acount >5 and acount <= 10 and ncount == 0:
|
||||||
|
return acount+ncount
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def __find_hm_fwver(txt):
|
def __find_hm_fwver(txt):
|
||||||
@ -143,7 +172,7 @@ class AddPage(rio.Component):
|
|||||||
if txt.find("BRS") == 0:
|
if txt.find("BRS") == 0:
|
||||||
a -= 1
|
a -= 1
|
||||||
if txt[a] in ['S', 'A']:
|
if txt[a] in ['S', 'A']:
|
||||||
return txt[a]
|
return '2' + txt[a]
|
||||||
a = __find_hm_fwver(txt)
|
a = __find_hm_fwver(txt)
|
||||||
if txt.find("GRS") == 0:
|
if txt.find("GRS") == 0:
|
||||||
a -= 4
|
a -= 4
|
||||||
@ -162,7 +191,7 @@ class AddPage(rio.Component):
|
|||||||
print(txt,txt[a])
|
print(txt,txt[a])
|
||||||
|
|
||||||
if txt[a] in ['P', 'E']:
|
if txt[a] in ['P', 'E']:
|
||||||
return txt[a]
|
return '2' + txt[a]
|
||||||
a = __find_hm_fwver(txt)
|
a = __find_hm_fwver(txt)
|
||||||
if txt.find("EAGLE") == 0:
|
if txt.find("EAGLE") == 0:
|
||||||
a -= 2
|
a -= 2
|
||||||
@ -179,7 +208,7 @@ class AddPage(rio.Component):
|
|||||||
if __find_hm_fwver(pn) >= 0:
|
if __find_hm_fwver(pn) >= 0:
|
||||||
self.fwver = pn[__find_hm_fwver(pn):]
|
self.fwver = pn[__find_hm_fwver(pn):]
|
||||||
if len(__find_hm_fwmode(pn)) > 0:
|
if len(__find_hm_fwmode(pn)) > 0:
|
||||||
self.fwver += " SWL-" + __find_hm_fwmode(pn)
|
self.fwver += " SW-L" + __find_hm_fwmode(pn)
|
||||||
|
|
||||||
def build(self) -> rio.Component:
|
def build(self) -> rio.Component:
|
||||||
return rio.Column(
|
return rio.Column(
|
||||||
@ -207,33 +236,39 @@ class AddPage(rio.Component):
|
|||||||
),
|
),
|
||||||
rio.TextInput(
|
rio.TextInput(
|
||||||
label="Serial",
|
label="Serial",
|
||||||
text=self.bind().serial
|
text=self.bind().serial,
|
||||||
|
on_confirm=self._add_part_enter
|
||||||
),
|
),
|
||||||
rio.TextInput(
|
rio.TextInput(
|
||||||
label="MAC",
|
label="MAC",
|
||||||
text=self.bind().mac,
|
text=self.bind().mac,
|
||||||
on_change=self._update_mac
|
on_change=self._update_mac,
|
||||||
|
on_confirm=self._add_part_enter
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Location (optional)",
|
||||||
|
text=self.bind().location,
|
||||||
|
on_change=self._update_location,
|
||||||
|
on_confirm=self._add_part_enter
|
||||||
),
|
),
|
||||||
rio.TextInput(
|
rio.TextInput(
|
||||||
label="Manufacturer",
|
label="Manufacturer",
|
||||||
text=self.bind().manufield
|
text=self.bind().manufield,
|
||||||
|
on_confirm=self._add_part_enter
|
||||||
),
|
),
|
||||||
rio.TextInput(
|
rio.TextInput(
|
||||||
label="FW Ver",
|
label="FW Ver",
|
||||||
text=self.bind().fwver,
|
text=self.bind().fwver
|
||||||
on_confirm=self._add_part_enter
|
|
||||||
),
|
),
|
||||||
rio.Row(
|
rio.MultiLineTextInput(
|
||||||
# rio.DateInput(
|
label="Description (optional)",
|
||||||
# label="Timestamp",
|
text=self.bind().description
|
||||||
# value=self.bind().date
|
),
|
||||||
# ),
|
rio.TextInput(
|
||||||
rio.TextInput(
|
label="Timestamp",
|
||||||
#text=
|
is_sensitive=False,
|
||||||
is_sensitive=False,
|
text = self.bind().time_start,
|
||||||
text = self.bind().time_start,
|
#on_change=self._set_time
|
||||||
#on_change=self._set_time
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
rio.Button(
|
rio.Button(
|
||||||
content="Add",
|
content="Add",
|
||||||
@ -241,7 +276,7 @@ class AddPage(rio.Component):
|
|||||||
),
|
),
|
||||||
|
|
||||||
spacing=2,
|
spacing=2,
|
||||||
width=60,
|
min_width=60,
|
||||||
margin_bottom=4,
|
margin_bottom=4,
|
||||||
align_x=0.5,
|
align_x=0.5,
|
||||||
align_y=0,
|
align_y=0,
|
||||||
|
@ -6,15 +6,36 @@ from typing import * # type: ignore
|
|||||||
import rio
|
import rio
|
||||||
|
|
||||||
from .. import components as comps
|
from .. import components as comps
|
||||||
|
from .add_page import AddPage
|
||||||
|
|
||||||
from db_classes import *
|
from db_classes import *
|
||||||
import functools
|
import functools
|
||||||
|
import asyncio
|
||||||
|
|
||||||
class BrowsePage(rio.Component):
|
class BrowsePage(rio.Component):
|
||||||
searchtext: str = ""
|
searchtext: str = ""
|
||||||
items: dict = {}
|
items: list = []
|
||||||
office: str = ""
|
office: str = ""
|
||||||
filters: dict = {}
|
filters: dict = {}
|
||||||
|
|
||||||
|
popup_message: str = ""
|
||||||
|
popup_show: bool = False
|
||||||
|
popup_color: str = 'success'
|
||||||
|
|
||||||
|
|
||||||
|
elocation: str = ""
|
||||||
|
elocation_code: str = ""
|
||||||
|
epartnum: str = ""
|
||||||
|
emac: str = ""
|
||||||
|
eserial: str = ""
|
||||||
|
efwver: str = ""
|
||||||
|
ecode: str = ""
|
||||||
|
emacvendor: str = ""
|
||||||
|
emanu: str = ""
|
||||||
|
emanufield: str = ""
|
||||||
|
eoffice: str = ""
|
||||||
|
edescription: str = ""
|
||||||
|
|
||||||
@rio.event.on_populate
|
@rio.event.on_populate
|
||||||
async def _search(self, query=searchtext):
|
async def _search(self, query=searchtext):
|
||||||
self.office = self.session[comps.Settings].office
|
self.office = self.session[comps.Settings].office
|
||||||
@ -35,24 +56,331 @@ class BrowsePage(rio.Component):
|
|||||||
async def _search_trigger(self, event: rio.TextInputChangeEvent):
|
async def _search_trigger(self, event: rio.TextInputChangeEvent):
|
||||||
await self._search(event.text)
|
await self._search(event.text)
|
||||||
|
|
||||||
def click_item(self, code):
|
async def _create_dialog_info(self, code: str) -> str | None:
|
||||||
|
async def copy_info(text: str):
|
||||||
|
await self.session.set_clipboard(text)
|
||||||
|
# TODO: show "Copied!" popup
|
||||||
|
self.popup_message = "\n Copied! \n\n"
|
||||||
|
self.popup_color = 'success'
|
||||||
|
self.popup_show = True
|
||||||
|
await asyncio.sleep(1.5)
|
||||||
|
self.popup_show = False
|
||||||
|
|
||||||
|
def build_dialog_info() -> rio.Component:
|
||||||
|
# Build the dialog
|
||||||
|
|
||||||
|
itm: dict = find_item(code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
loc = itm["location"]
|
||||||
|
except:
|
||||||
|
loc = ""
|
||||||
|
if itm["checkout"]:
|
||||||
|
checkout = itm["checkout_user"] + " - " + loc
|
||||||
|
else:
|
||||||
|
checkout = loc
|
||||||
|
|
||||||
|
details: rio.ListView = rio.ListView(grow_y=True, min_width=40)
|
||||||
|
# for key, val in itm.items():
|
||||||
|
# details.add(rio.SimpleListItem(text=key,secondary_text=val))
|
||||||
|
#functools.partial(copy_info, text=item["barcode"])
|
||||||
|
name=str(itm["fullname"])
|
||||||
|
manu=str(itm["manufacturer"])
|
||||||
|
serial=str(itm["serial"])
|
||||||
|
mac=str(itm["mac"])
|
||||||
|
fw=str(itm["fwver"])
|
||||||
|
loc=str(checkout)
|
||||||
|
checkouts=str(itm["checkout"])
|
||||||
|
checkout_times=str(itm["checkout_start"]) + " to " + str(itm["checkout_end"])
|
||||||
|
#office=str(itm["office"])
|
||||||
|
barcode=str(itm["barcode"])
|
||||||
|
desc=str(itm["description"])
|
||||||
|
details.add(rio.SimpleListItem(text=name, on_press=functools.partial(copy_info, text=name)))
|
||||||
|
details.add(rio.SimpleListItem(text=manu, on_press=functools.partial(copy_info, text=manu)))
|
||||||
|
details.add(rio.SimpleListItem(text="Serial",secondary_text=serial, on_press=functools.partial(copy_info, text=serial)))
|
||||||
|
details.add(rio.SimpleListItem(text="MAC",secondary_text=mac, on_press=functools.partial(copy_info, text=mac)))
|
||||||
|
details.add(rio.SimpleListItem(text="FW Version",secondary_text=fw, on_press=functools.partial(copy_info, text=fw)))
|
||||||
|
details.add(rio.SimpleListItem(text="Location",secondary_text=loc, on_press=functools.partial(copy_info, text=loc)))
|
||||||
|
details.add(rio.SimpleListItem(text="Checked out?",secondary_text=checkouts, on_press=functools.partial(copy_info, text=checkouts)))
|
||||||
|
details.add(rio.SimpleListItem(text="Checkout start/end",secondary_text=checkout_times, on_press=functools.partial(copy_info, text=checkout_times)))
|
||||||
|
#details.add(rio.SimpleListItem(text="Office",secondary_text=office, on_press=functools.partial(copy_info, text=office)))
|
||||||
|
details.add(rio.SimpleListItem(text="Barcode",secondary_text=barcode, on_press=functools.partial(copy_info, text=barcode)))
|
||||||
|
details.add(rio.SimpleListItem(text="Description",secondary_text=desc, on_press=functools.partial(copy_info, text=desc)))
|
||||||
|
|
||||||
|
return rio.Card(
|
||||||
|
rio.Column(
|
||||||
|
details,
|
||||||
|
rio.Row(
|
||||||
|
rio.Button(
|
||||||
|
content="Close",
|
||||||
|
on_press=_close_dialog_info
|
||||||
|
),
|
||||||
|
rio.Button(
|
||||||
|
content="Edit",
|
||||||
|
on_press=functools.partial(self._create_dialog_edit, code=code)
|
||||||
|
),
|
||||||
|
spacing=2,
|
||||||
|
margin=2
|
||||||
|
),
|
||||||
|
spacing=1,
|
||||||
|
margin=2,
|
||||||
|
),
|
||||||
|
align_x=0.5,
|
||||||
|
align_y=0.5,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _close_dialog_info() -> None:
|
||||||
|
# This function will be called whenever the user selects an
|
||||||
|
# Item. It simply closes the dialog with the selected value.
|
||||||
|
await dialog.close()
|
||||||
|
|
||||||
|
dialog = await self.session.show_custom_dialog(
|
||||||
|
build=build_dialog_info,
|
||||||
|
# Prevent the user from interacting with the rest of the app
|
||||||
|
# while the dialog is open
|
||||||
|
modal=True,
|
||||||
|
# Don't close the dialog if the user clicks outside of it
|
||||||
|
user_closeable=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for the user to select an option
|
||||||
|
result = await dialog.wait_for_close()
|
||||||
|
|
||||||
|
# Return the selected value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
async def _create_dialog_edit(self, code: str) -> str | None:
|
||||||
|
itm: dict = find_item(code)
|
||||||
|
from mac_vendor_lookup import AsyncMacLookup
|
||||||
|
try:
|
||||||
|
self.elocation: str = itm["location"]
|
||||||
|
self.elocation_code: str = find_item_location(code).locationid
|
||||||
|
except:
|
||||||
|
self.elocation: str = ""
|
||||||
|
self.elocation_code: str = ""
|
||||||
|
|
||||||
|
self.epartnum: str = itm["fullname"]
|
||||||
|
self.emac: str = itm["mac"]
|
||||||
|
self.eserial: str = itm["serial"]
|
||||||
|
self.efwver: str = itm["fwver"]
|
||||||
|
self.ecode: str = code
|
||||||
|
self.popup_message: str = ""
|
||||||
|
self.popup_show: bool = False
|
||||||
|
self.popup_color: str = 'warning'
|
||||||
|
self.emacvendor: str = ""
|
||||||
|
self.emanu: str = itm["manufacturer"]
|
||||||
|
self.emanufield: str = itm["manufacturer"]
|
||||||
|
self.eoffice: str = itm["office"]
|
||||||
|
self.edescription: str = itm["description"]
|
||||||
|
|
||||||
|
async def check_mac(mac):
|
||||||
|
print("Checking", mac)
|
||||||
|
self.emac = mac
|
||||||
|
try:
|
||||||
|
macvendor = await AsyncMacLookup().lookup(mac)
|
||||||
|
if self.emanufield == "" or self.emanufield == self.emacvendor: # blank or set by MAC already
|
||||||
|
self.emanu = macvendor
|
||||||
|
self.emanufield = macvendor
|
||||||
|
else:
|
||||||
|
self.emanu = self.emanufield
|
||||||
|
self.emacvendor = macvendor
|
||||||
|
#print(macvendor)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# not valid MAC?
|
||||||
|
|
||||||
|
async def check_all():
|
||||||
|
await check_mac(self.emac)
|
||||||
|
# check part number
|
||||||
|
# lookup in PL_Export_rel
|
||||||
|
|
||||||
|
async def add_part():
|
||||||
|
await check_all()
|
||||||
|
if self.ecode == "":
|
||||||
|
# FAIL
|
||||||
|
self.popup_message = "\n Missing barcode! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'danger'
|
||||||
|
|
||||||
|
else:
|
||||||
|
# OK, add part
|
||||||
|
if update_item(self.epartnum, self.eserial, self.office, self.ecode, locationid=self.elocation_code, description=self.edescription, manufacturer=self.emanu, mac=self.emac, fwver=self.efwver) == False:
|
||||||
|
self.popup_message = "\n Unable to update! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'warning'
|
||||||
|
else:
|
||||||
|
self.popup_message = "\n Part updated! \n\n"
|
||||||
|
self.popup_show = True
|
||||||
|
self.popup_color = 'success'
|
||||||
|
#self.ename: str = ""
|
||||||
|
self.epartnum: str = ""
|
||||||
|
self.emac: str = ""
|
||||||
|
self.eserial: str = ""
|
||||||
|
self.efwver: str = ""
|
||||||
|
self.ecode: str = ""
|
||||||
|
self.emacvendor: str = ""
|
||||||
|
self.emanu: str = ""
|
||||||
|
self.emanufield: str = ""
|
||||||
|
self.edescription: str = ""
|
||||||
|
self.elocation: str = ""
|
||||||
|
self.elocation_code: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
async def _add_part_enter(event: rio.TextInputConfirmEvent):
|
||||||
|
await add_part()
|
||||||
|
|
||||||
|
async def _add_part_button():
|
||||||
|
await add_part()
|
||||||
|
|
||||||
|
async def _update_mac(event: rio.TextInputChangeEvent):
|
||||||
|
await check_mac(event.text)
|
||||||
|
|
||||||
|
async def _update_location(event: rio.TextInputChangeEvent):
|
||||||
|
print("Checking " + event.text)
|
||||||
|
self.elocation = event.text
|
||||||
|
if get_location_id(event.text) != False:
|
||||||
|
self.elocation_code = event.text
|
||||||
|
print("Found location " + get_location_id(event.text).name)
|
||||||
|
self.elocation = get_location_id(event.text).name
|
||||||
|
|
||||||
|
async def _update_epartnum(event: rio.TextInputChangeEvent):
|
||||||
|
self.epartnum = event.text
|
||||||
|
|
||||||
|
async def _update_eserial(event: rio.TextInputChangeEvent):
|
||||||
|
self.eserial = event.text
|
||||||
|
|
||||||
|
async def _update_emanufield(event: rio.TextInputChangeEvent):
|
||||||
|
self.emanufield = event.text
|
||||||
|
self.emanu = event.text
|
||||||
|
|
||||||
|
async def _update_efwver(event: rio.TextInputChangeEvent):
|
||||||
|
self.efwver = event.text
|
||||||
|
|
||||||
|
async def _update_edescription(event: rio.TextInputChangeEvent):
|
||||||
|
self.edescription = event.text
|
||||||
|
|
||||||
|
def build_dialog_edit() -> rio.Component:
|
||||||
|
# Build the dialog
|
||||||
|
return rio.Card(
|
||||||
|
rio.Column(
|
||||||
|
rio.TextInput(
|
||||||
|
label="Barcode",
|
||||||
|
text=self.ecode,
|
||||||
|
is_sensitive=False
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Full part number",
|
||||||
|
text=self.epartnum,
|
||||||
|
on_change=_update_epartnum
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Serial",
|
||||||
|
text=self.eserial,
|
||||||
|
on_change=_update_eserial
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="MAC",
|
||||||
|
text=self.emac,
|
||||||
|
on_change=_update_mac,
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Location (optional)",
|
||||||
|
text=self.elocation,
|
||||||
|
on_change=_update_location,
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="Manufacturer",
|
||||||
|
text=self.emanufield,
|
||||||
|
on_change=_update_emanufield
|
||||||
|
),
|
||||||
|
rio.TextInput(
|
||||||
|
label="FW Ver",
|
||||||
|
text=self.efwver,
|
||||||
|
on_change=_update_efwver
|
||||||
|
),
|
||||||
|
rio.MultiLineTextInput(
|
||||||
|
label="Description (optional)",
|
||||||
|
text=self.edescription,
|
||||||
|
on_change=_update_edescription
|
||||||
|
),
|
||||||
|
|
||||||
|
rio.Row(
|
||||||
|
rio.Button(
|
||||||
|
content="Cancel",
|
||||||
|
on_press=_close_dialog_edit,
|
||||||
|
color='warning'
|
||||||
|
),
|
||||||
|
rio.Button(
|
||||||
|
content="Delete",
|
||||||
|
on_press=_delete_dialog_edit,
|
||||||
|
color='danger'
|
||||||
|
),
|
||||||
|
rio.Button(
|
||||||
|
content="Save",
|
||||||
|
on_press=_save_dialog_edit
|
||||||
|
),
|
||||||
|
spacing=2,
|
||||||
|
margin=2
|
||||||
|
),
|
||||||
|
spacing=1,
|
||||||
|
margin=2
|
||||||
|
),
|
||||||
|
align_x=0.5,
|
||||||
|
align_y=0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _close_dialog_edit() -> None:
|
||||||
|
await dialog.close()
|
||||||
|
|
||||||
|
async def _save_dialog_edit() -> None:
|
||||||
|
await dialog.close()
|
||||||
|
await _add_part_button()
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.popup_show = False
|
||||||
|
|
||||||
|
async def _delete_dialog_edit() -> None:
|
||||||
|
await dialog.close()
|
||||||
|
|
||||||
|
dialog = await self.session.show_custom_dialog(
|
||||||
|
build=build_dialog_edit,
|
||||||
|
# Prevent the user from interacting with the rest of the app
|
||||||
|
# while the dialog is open
|
||||||
|
modal=True,
|
||||||
|
# Don't close the dialog if the user clicks outside of it
|
||||||
|
user_closeable=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for the user to select an option
|
||||||
|
result = await dialog.wait_for_close()
|
||||||
|
|
||||||
|
# Return the selected value
|
||||||
|
return result
|
||||||
|
|
||||||
|
def click_item_page(self, code):
|
||||||
self.session[comps.Settings].selected_item = code
|
self.session[comps.Settings].selected_item = code
|
||||||
self.session.attach(self.session[comps.Settings])
|
self.session.attach(self.session[comps.Settings])
|
||||||
self.session.navigate_to("/item")
|
self.session.navigate_to("/item")
|
||||||
|
|
||||||
|
async def click_item_dialog(self, code):
|
||||||
|
self.session[comps.Settings].selected_item = code
|
||||||
|
#self.session.attach(self.session[comps.Settings])
|
||||||
|
#self.session.navigate_to("/item")
|
||||||
|
ret = await self._create_dialog_info(code)
|
||||||
|
|
||||||
def build(self) -> rio.Component:
|
def build(self) -> rio.Component:
|
||||||
searchview: rio.ListView = rio.ListView(height='grow')
|
searchview: rio.ListView = rio.ListView(grow_y=True)
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
if item["loc"] is not None:
|
try:
|
||||||
loc = item["loc"]["name"]
|
loc = item["location"]
|
||||||
else:
|
except:
|
||||||
loc = ""
|
loc = ""
|
||||||
if item["checkout"]:
|
if item["checkout"]:
|
||||||
checkout = item["checkout_user"] + " - " + loc
|
checkout = item["checkout_user"] + " - " + loc
|
||||||
else:
|
else:
|
||||||
checkout = loc
|
checkout = loc
|
||||||
searchview.add(rio.SimpleListItem(text=item["fullname"],secondary_text=(item["manufacturer"] + " - Serial: " + item["serial"] + "\n" + checkout), on_press=functools.partial(
|
searchview.add(rio.SimpleListItem(text=item["fullname"],secondary_text=(item["manufacturer"] + " - Serial: " + item["serial"] + "\n" + checkout), on_press=functools.partial(
|
||||||
self.click_item,
|
self.click_item_dialog,
|
||||||
code=item["barcode"])))
|
code=item["barcode"])))
|
||||||
return rio.Column(
|
return rio.Column(
|
||||||
rio.Row(
|
rio.Row(
|
||||||
@ -63,8 +391,21 @@ class BrowsePage(rio.Component):
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
searchview,
|
searchview,
|
||||||
|
rio.Popup(
|
||||||
|
anchor=rio.Text(
|
||||||
|
text="",
|
||||||
|
style='heading1',
|
||||||
|
align_x = 0.5
|
||||||
|
),
|
||||||
|
color=self.popup_color,
|
||||||
|
is_open=self.popup_show,
|
||||||
|
content=rio.Text(
|
||||||
|
text=self.popup_message,
|
||||||
|
),
|
||||||
|
|
||||||
|
),
|
||||||
spacing=2,
|
spacing=2,
|
||||||
width=60,
|
min_width=60,
|
||||||
align_x=0.5,
|
align_x=0.5,
|
||||||
align_y=0,
|
align_y=0,
|
||||||
)
|
)
|
||||||
|
@ -92,7 +92,7 @@ class ItemPage(rio.Component):
|
|||||||
align_x = 0.5,
|
align_x = 0.5,
|
||||||
),
|
),
|
||||||
spacing=2,
|
spacing=2,
|
||||||
width=60,
|
min_width=60,
|
||||||
align_x=0.5,
|
align_x=0.5,
|
||||||
align_y=0,
|
align_y=0,
|
||||||
)
|
)
|
||||||
|
@ -27,11 +27,11 @@ class RootPage(rio.Component):
|
|||||||
# of all other components.
|
# of all other components.
|
||||||
comps.Navbar(),
|
comps.Navbar(),
|
||||||
# Add some empty space so the navbar doesn't cover the content.
|
# Add some empty space so the navbar doesn't cover the content.
|
||||||
rio.Spacer(height=10),
|
rio.Spacer(min_height=10),
|
||||||
# The page view will display the content of the current page.
|
# The page view will display the content of the current page.
|
||||||
rio.PageView(
|
rio.PageView(
|
||||||
# Make sure the page view takes up all available space.
|
# Make sure the page view takes up all available space.
|
||||||
height="grow",
|
grow_y=True
|
||||||
),
|
),
|
||||||
# The footer is also common to all pages, so place it here.
|
# The footer is also common to all pages, so place it here.
|
||||||
comps.Footer(),
|
comps.Footer(),
|
||||||
|
26
inventory/pages/settings_page.py
Normal file
26
inventory/pages/settings_page.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import KW_ONLY, field
|
||||||
|
from typing import * # type: ignore
|
||||||
|
|
||||||
|
import rio
|
||||||
|
|
||||||
|
from .. import components as comps
|
||||||
|
|
||||||
|
class SettingsPage(rio.Component):
|
||||||
|
"""
|
||||||
|
A sample page, which displays a humorous description of the company.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def build(self) -> rio.Component:
|
||||||
|
return rio.Markdown(
|
||||||
|
"""
|
||||||
|
Belden Inventory manager v0.5
|
||||||
|
WIP
|
||||||
|
""",
|
||||||
|
min_width=60,
|
||||||
|
margin_bottom=4,
|
||||||
|
align_x=0.5,
|
||||||
|
align_y=0,
|
||||||
|
)
|
||||||
|
|
@ -1,6 +1,5 @@
|
|||||||
peewee
|
peewee
|
||||||
pymysql
|
pymysql
|
||||||
flask
|
rio-ui==0.10.4
|
||||||
rio-ui
|
meilisearch #==0.31.5
|
||||||
meilisearch
|
|
||||||
mac-vendor-lookup
|
mac-vendor-lookup
|
@ -1,6 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""Interactions with the Meilisearch API for adding and searching cables."""
|
"""Interactions with the Meilisearch API for adding and searching cables."""
|
||||||
|
import sys
|
||||||
|
|
||||||
from meilisearch import Client
|
from meilisearch import Client
|
||||||
from meilisearch.task import TaskInfo
|
from meilisearch.task import TaskInfo
|
||||||
from meilisearch.errors import MeilisearchApiError
|
from meilisearch.errors import MeilisearchApiError
|
||||||
@ -45,6 +47,8 @@ class InventorySearch:
|
|||||||
# make a variable to easily reference the index
|
# make a variable to easily reference the index
|
||||||
self.idxref = self.client.index(self.index)
|
self.idxref = self.client.index(self.index)
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
# disable typos, we have serial numbers and such that should be exact match
|
||||||
|
self.idxref.update_typo_tolerance({'enabled': False})
|
||||||
# update filterable attributes if needed
|
# update filterable attributes if needed
|
||||||
self.idxref.update_distinct_attribute('barcode')
|
self.idxref.update_distinct_attribute('barcode')
|
||||||
self.update_filterables(filterable_attrs)
|
self.update_filterables(filterable_attrs)
|
||||||
@ -109,4 +113,4 @@ class InventorySearch:
|
|||||||
|
|
||||||
# entrypoint
|
# entrypoint
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
jbs = InventorySearch()
|
ivs = InventorySearch()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user