mwe full cycle form input
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import os, sys, subprocess, json, click, time, re
|
||||
|
||||
from ffx.modes_app import ModesApp
|
||||
from ffx.ffx_app import FfxApp
|
||||
|
||||
VERSION='0.1.0'
|
||||
|
||||
@@ -391,7 +391,7 @@ def unmux(ctx,
|
||||
|
||||
def shows(ctx):
|
||||
|
||||
app = ModesApp(ctx.obj)
|
||||
app = FfxApp(ctx.obj)
|
||||
app.run()
|
||||
|
||||
|
||||
|
||||
67
bin/ffx/ffx_app.py
Normal file
67
bin/ffx/ffx_app.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import os
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from ffx.model.show import Base, Show
|
||||
from ffx.model.pattern import Pattern
|
||||
|
||||
from .shows_screen import ShowsScreen
|
||||
from .warning_screen import WarningScreen
|
||||
from .dashboard_screen import DashboardScreen
|
||||
from .settings_screen import SettingsScreen
|
||||
from .help_screen import HelpScreen
|
||||
|
||||
class FfxApp(App):
|
||||
|
||||
TITLE = "FFX"
|
||||
|
||||
BINDINGS = [
|
||||
("q", "quit()", "Quit"),
|
||||
# ("d", "switch_mode('dashboard')", "Dashboard"),
|
||||
# ("s", "switch_mode('settings')", "Settings"),
|
||||
("h", "switch_mode('help')", "Help"),
|
||||
]
|
||||
|
||||
# MODES = {
|
||||
# "shows": ShowsScreen,
|
||||
# "warning": WarningScreen,
|
||||
# "dashboard": DashboardScreen,
|
||||
# "settings": SettingsScreen,
|
||||
# "help": HelpScreen,
|
||||
# }
|
||||
|
||||
|
||||
def __init__(self, context = {}):
|
||||
super().__init__()
|
||||
|
||||
# Data 'input' variable
|
||||
self.context = context
|
||||
|
||||
# Initialize DB
|
||||
homeDir = os.path.expanduser("~")
|
||||
ffxVarDir = os.path.join(homeDir, '.local', 'var', 'ffx')
|
||||
if not os.path.exists(ffxVarDir):
|
||||
os.makedirs(ffxVarDir)
|
||||
|
||||
self.context['database_url'] = f"sqlite:///{os.path.join(ffxVarDir, 'ffx.db')}"
|
||||
self.context['database_engine'] = create_engine(self.context['database_url'])
|
||||
self.context['database_session'] = sessionmaker(bind=self.context['database_engine'])
|
||||
|
||||
Base.metadata.create_all(self.context['database_engine'])
|
||||
|
||||
|
||||
def on_mount(self) -> None:
|
||||
|
||||
|
||||
# Show Shows Screen
|
||||
#self.switch_mode("shows")
|
||||
self.push_screen(ShowsScreen())
|
||||
|
||||
|
||||
def getContext(self):
|
||||
"""Data 'output' method"""
|
||||
return self.context
|
||||
@@ -1,2 +0,0 @@
|
||||
class FilePattern():
|
||||
pass
|
||||
0
bin/ffx/model/__init__.py
Normal file
0
bin/ffx/model/__init__.py
Normal file
10
bin/ffx/model/pattern.py
Normal file
10
bin/ffx/model/pattern.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
|
||||
from sqlalchemy.orm import relationship, sessionmaker
|
||||
|
||||
from .show import Base
|
||||
|
||||
class Pattern(Base):
|
||||
|
||||
__tablename__ = 'patterns'
|
||||
id = Column(Integer, primary_key=True)
|
||||
pattern = Column(String)
|
||||
13
bin/ffx/model/show.py
Normal file
13
bin/ffx/model/show.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
|
||||
from sqlalchemy.orm import relationship, sessionmaker
|
||||
|
||||
from sqlalchemy.orm import declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class Show(Base):
|
||||
|
||||
__tablename__ = 'shows'
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
year = Column(Integer)
|
||||
@@ -1,39 +0,0 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label
|
||||
|
||||
from .shows_screen import ShowsScreen
|
||||
from .warning_screen import WarningScreen
|
||||
from .dashboard_screen import DashboardScreen
|
||||
from .settings_screen import SettingsScreen
|
||||
from .help_screen import HelpScreen
|
||||
|
||||
class ModesApp(App):
|
||||
|
||||
TITLE = "FFX"
|
||||
|
||||
BINDINGS = [
|
||||
("q", "quit()", "Quit"),
|
||||
# ("d", "switch_mode('dashboard')", "Dashboard"),
|
||||
# ("s", "switch_mode('settings')", "Settings"),
|
||||
# ("h", "switch_mode('help')", "Help"),
|
||||
]
|
||||
|
||||
MODES = {
|
||||
"shows": ShowsScreen,
|
||||
"warning": WarningScreen,
|
||||
"dashboard": DashboardScreen,
|
||||
"settings": SettingsScreen,
|
||||
"help": HelpScreen,
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, context = {}):
|
||||
super().__init__()
|
||||
self.context = context
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.switch_mode("shows")
|
||||
|
||||
def getContext(self):
|
||||
return self.context
|
||||
@@ -1,2 +0,0 @@
|
||||
class Show():
|
||||
pass
|
||||
166
bin/ffx/show_details_screen.py
Normal file
166
bin/ffx/show_details_screen.py
Normal file
@@ -0,0 +1,166 @@
|
||||
import click
|
||||
|
||||
from textual import events
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
from ffx.model.show import Show
|
||||
|
||||
# class IdInput(Input):
|
||||
# def on_key(self, event: events.Key) -> None:
|
||||
# if event == "enter":
|
||||
# quit()
|
||||
|
||||
class ShowDetailsScreen(Screen):
|
||||
|
||||
CSS = """
|
||||
|
||||
Grid {
|
||||
grid-size: 2;
|
||||
grid-rows: 2 auto;
|
||||
grid-columns: 30 auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
Input {
|
||||
border: none;
|
||||
}
|
||||
Button {
|
||||
border: none;
|
||||
}
|
||||
#toplabel {
|
||||
height: 1;
|
||||
column-span: 2;
|
||||
}
|
||||
|
||||
|
||||
#two {
|
||||
column-span: 2;
|
||||
row-span: 2;
|
||||
tint: magenta 40%;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
}
|
||||
"""
|
||||
|
||||
#BINDINGS = [
|
||||
# #("q", "quit()", "Quit"),
|
||||
# ("h", "switch_mode('help')", "Help")
|
||||
#]
|
||||
|
||||
#def action_quit(self):
|
||||
# quit()
|
||||
|
||||
def __init__(self, show_id = None):
|
||||
super().__init__()
|
||||
|
||||
self.context = self.app.getContext()
|
||||
|
||||
self.Session = self.context['database_session'] # convenience
|
||||
|
||||
self.show_id = show_id
|
||||
|
||||
def action_submit(self):
|
||||
quit()
|
||||
|
||||
def compose(self):
|
||||
|
||||
yield Header()
|
||||
|
||||
with Grid():
|
||||
|
||||
yield Static("New Show" if self.show_id is None else "Show", id="toplabel")
|
||||
yield Static("ID")
|
||||
yield Input(type="text", id="id_input")
|
||||
yield Static("Name")
|
||||
yield Input(type="text", id="name_input")
|
||||
yield Static("Year")
|
||||
yield Input(type="text", id="year_input")
|
||||
|
||||
yield Static("")
|
||||
yield Static("")
|
||||
|
||||
yield Static("")
|
||||
yield Static("")
|
||||
|
||||
yield Button("Save", id="save_button")
|
||||
yield Button("Cancel", id="cancel_button")
|
||||
|
||||
yield Static("", id="output_static")
|
||||
|
||||
|
||||
yield Footer()
|
||||
|
||||
def getValues(self):
|
||||
showId = int(self.query_one("#id_input", Input).value)
|
||||
showName = self.query_one("#name_input", Input).value
|
||||
showYear = self.query_one("#year_input", Input).value
|
||||
return showId, showName, showYear
|
||||
|
||||
|
||||
def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||
|
||||
showId, showName, showYear = self.getValues()
|
||||
|
||||
#self.query_one("#output_static", Static).update(f"{showId} - {showName} ({showYear})")
|
||||
|
||||
# if event.input.id == "id_input":
|
||||
# # Retrieve the entered text
|
||||
# name = event.value
|
||||
# # Display the result in the output label
|
||||
# self.query_one("#output_static", Static).update(f"Hello, {name}!")
|
||||
# self.set_focus(self.query_one("#name_input", Input))
|
||||
#
|
||||
# if event.input.id == "name_input":
|
||||
# # Retrieve the entered text
|
||||
# name = event.value
|
||||
# # Display the result in the output label
|
||||
# self.query_one("#output_static", Static).update(f"Yo, {name}!")
|
||||
# self.set_focus(self.query_one("#year_input", Input))
|
||||
#
|
||||
# if event.input.id == "year_input":
|
||||
# # Retrieve the entered text
|
||||
# name = event.value
|
||||
# # Display the result in the output label
|
||||
# self.query_one("#output_static", Static).update(f"Ya, {name}!")
|
||||
# self.set_focus(None)
|
||||
|
||||
# Event handler for button press
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
# Check if the button pressed is the one we are interested in
|
||||
if event.button.id == "save_button":
|
||||
|
||||
showId, showName, showYear = self.getValues()
|
||||
self.query_one("#output_static", Static).update(f"{showId} - {showName} ({showYear})")
|
||||
|
||||
self.addShow(showId, showName, showYear)
|
||||
#TODO: Validation
|
||||
|
||||
# self.app.pop_screen()
|
||||
self.dismiss(showId)
|
||||
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
|
||||
def addShow(self, show_id, show_name, show_year):
|
||||
|
||||
try:
|
||||
s = self.Session()
|
||||
show = Show(id = show_id,
|
||||
name = show_name,
|
||||
year = show_year)
|
||||
|
||||
s.add(show)
|
||||
s.commit()
|
||||
except Exception as ex:
|
||||
click.ClickException(f"ShowDetailsScreen.addShow(): {repr(ex)}")
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
60
bin/ffx/show_new_screen.py
Normal file
60
bin/ffx/show_new_screen.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import click
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
from ffx.model.show import Show
|
||||
|
||||
class ShowNewScreen(Screen):
|
||||
|
||||
CSS = """
|
||||
|
||||
Grid {
|
||||
grid-size: 2;
|
||||
grid-rows: 2 auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
#top {
|
||||
height: 1;
|
||||
}
|
||||
|
||||
|
||||
#two {
|
||||
column-span: 2;
|
||||
row-span: 2;
|
||||
tint: magenta 40%;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
}
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
("q", "quit()", "Quit"),
|
||||
("h", "switch_mode('help')", "Help")
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.context = self.app.getContext()
|
||||
|
||||
self.Session = self.context['database_session'] # convenience
|
||||
|
||||
|
||||
def compose(self):
|
||||
|
||||
yield Header()
|
||||
|
||||
with Grid():
|
||||
|
||||
yield Static("New Show")
|
||||
|
||||
yield Footer()
|
||||
@@ -1,9 +1,16 @@
|
||||
import click
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
from ffx.model.show import Show
|
||||
|
||||
from .show_details_screen import ShowDetailsScreen
|
||||
from .show_new_screen import ShowNewScreen
|
||||
from .help_screen import HelpScreen
|
||||
|
||||
|
||||
class ShowsScreen(Screen):
|
||||
|
||||
@@ -35,51 +42,95 @@ class ShowsScreen(Screen):
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
("q", "quit()", "Quit"),
|
||||
("e", "switch_mode('settings')", "Edit Show"),
|
||||
("n", "switch_mode('dashboard')", "New Show")
|
||||
# ("h", "switch_mode('help')", "Help"),
|
||||
#("q", "quit()", "Quit"),
|
||||
("e", "switch_mode('show_details')", "Edit Show"),
|
||||
("n", "new_show", "New Show"),
|
||||
#("h", "switch_mode('help')", "Help")
|
||||
]
|
||||
|
||||
# MODES = {
|
||||
# "show_details": ShowDetailsScreen,
|
||||
# "show_new": ShowNewScreen,
|
||||
# "help": HelpScreen,
|
||||
# }
|
||||
|
||||
def action_new_show(self):
|
||||
self.app.push_screen(ShowDetailsScreen(), self.handle_new_screen)
|
||||
|
||||
|
||||
def handle_new_screen(self, showId):
|
||||
|
||||
showList = self.loadShows()
|
||||
|
||||
for show in showList:
|
||||
if show[0] == showId:
|
||||
self.table.add_row(*map(str, show))
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
context = self.app.getContext()
|
||||
context['dashboard'] = 'dashboard'
|
||||
self.context = self.app.getContext()
|
||||
|
||||
self.Session = self.context['database_session'] # convenience
|
||||
|
||||
|
||||
def loadShows(self):
|
||||
|
||||
try:
|
||||
s = self.Session()
|
||||
q = s.query(Show)
|
||||
|
||||
return [(int(s.id), s.name, s.year) for s in q.all()]
|
||||
|
||||
except Exception as ex:
|
||||
click.ClickException(f"ShowsScreen(): {repr(ex)}")
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
||||
def on_mount(self) -> None:
|
||||
for show in self.loadShows():
|
||||
self.table.add_row(*map(str, show)) # Convert each element to a string before adding
|
||||
|
||||
|
||||
#def on_resume(self) -> None:
|
||||
|
||||
# quit()
|
||||
|
||||
# showList = self.loadShows()
|
||||
#
|
||||
# tableIdSet = set({int(r[0]) for r in self.table.rows})
|
||||
# databaseIdSet = set({int(s[0]) for s in showList})
|
||||
#
|
||||
# missingIdSet = databaseIdSet - tableIdSet
|
||||
# removedIdSet = tableIdSet - databaseIdSet
|
||||
#
|
||||
# for show in showList:
|
||||
# if show[0] in missingIdSet:
|
||||
# self.table.add_row(*map(str, show))
|
||||
|
||||
|
||||
|
||||
def compose(self):
|
||||
|
||||
# Create the DataTable widget
|
||||
table = DataTable()
|
||||
self.table = DataTable()
|
||||
|
||||
# Define the columns with headers
|
||||
table.add_column("ID", width=10)
|
||||
table.add_column("Name", width=20)
|
||||
table.add_column("Age", width=10)
|
||||
table.add_column("Country", width=20)
|
||||
self.table.add_column("ID", width=10)
|
||||
self.table.add_column("Name", width=50)
|
||||
self.table.add_column("Year", width=10)
|
||||
|
||||
table.cursor_type = 'row'
|
||||
|
||||
# Sample data for rows
|
||||
data = [
|
||||
(1, "John Doe", 28, "USA"),
|
||||
(2, "Jane Smith", 34, "Canada"),
|
||||
(3, "Alice Johnson", 29, "UK"),
|
||||
(4, "Bob Brown", 45, "Australia"),
|
||||
(5, "Charlie Davis", 23, "USA"),
|
||||
]
|
||||
|
||||
# Add rows to the table
|
||||
for i in range(20):
|
||||
for row in data:
|
||||
table.add_row(*map(str, row)) # Convert each element to a string before adding
|
||||
self.table.cursor_type = 'row'
|
||||
|
||||
yield Header()
|
||||
|
||||
with Grid():
|
||||
|
||||
yield Static("Shows") # , classes="box"
|
||||
yield Static("Shows")
|
||||
|
||||
yield table
|
||||
yield self.table
|
||||
|
||||
yield Footer()
|
||||
|
||||
Reference in New Issue
Block a user