Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@


class MyApp(App):
CSS_PATH = "./my_reports.tcss"
CSS_PATH = "my_reports.tcss"

BINDINGS = [
("q", "quit", "Quit"),
Expand Down
83 changes: 83 additions & 0 deletions my_egeria/my_egeria/DemoCode/My_Profile/AddCommentScreen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
""""
PDX-License-Identifier: Apache-2.0
Copyright Contributors to the ODPi Egeria project.

This file provides a screen for a user to show cooments attached to a community for my_egeria.

"""
from textual import on
from textual.app import ComposeResult
from textual.containers import ScrollableContainer
from textual.screen import ModalScreen
from textual.widgets import Header, Static, Footer, Input, Button, DataTable

from pyegeria import load_app_config, settings


class AddCommentScreen(ModalScreen):
""" Add a comment to an Egeria Element the user has access to """

BINDINGS = [
("a", "add_comment", "Add Comment"),
("c", "cancel", "Cancel"),
("q", "quit", "Quit")
]

CSS_PATH = "my_profile.tcss"

def __init__(self, table_name, element_guid, *args, **kwargs):
super().__init__(*args, **kwargs)
self.table_name = table_name
self.element_guid = element_guid or None
load_app_config()
app_config = settings.Environment
app_user = settings.User_Profile
self.view_server = app_config.egeria_view_server or "qs-view-server"
self.platform_url = (app_config.egeria_platform_url or "https://127.0.0.1:9443")
self.user_name = app_user.user_name or "garygeeke"
self.user_password = app_user.user_pwd or "secret"

def on_mount(self):
self.title = "Egeria - My Profile"
self.subtitle = "Add a comment to an element in Egeria"
if self.element_guid == None:
self.notify(f"A row must be selected from a table on the main screen before adding a comment")
self.dismiss(400)

def compose(self) -> ComposeResult:
"""This method composes the UI for the AddCommentScreen."""
yield Header(show_clock=True)
yield Static(classes="empty")
yield ScrollableContainer(
Static(f"[b]Add Comment[/b] to {self.element_guid}"),
Input(placeholder="Enter comment", id="add_comment_input"),
Static(f"Valid comment types are: Question, Answer, Suggestion and Requirement"),
Input(placeholder="Comment Type: Question, Suggestion, etc.", id="add_comment_type_input"),
Static("Use Cancel to return to the previous screen"),
Button("Submit", id="add_comment_button", variant="primary"),
id="add_comment_container"
)
yield Footer()

def action_quit(self):
self.dismiss(200)

def action_cancel(self):
self.dismiss(200)

@on(Button.Pressed, "#add_comment_button")
def handle_button_pressed(self):
if self.comment and self.comment_type:
self.comment_data = [self.comment, self.comment_type, self.element_guid]
self.log(f"Comment data: {self.comment_data} being returned from screen")
self.dismiss(self.comment_data)
else:
self.notify("Please enter both a comment and comment type, before submitting")

def on_input_changed(self, event: Input.Changed):
self.log(f"Input detected: {event.input.id}, {event.input.value}")
if event.input.id == "add_comment_input":
self.comment = event.value
elif event.input.id == "add_comment_type_input":
self.comment_type = event.value

Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ def action_add_new_blog(self):
self.query_one("#blog_entry_name", Input).clear()
self.query_one("#blog_entry_text", Input).clear()
self.query_one("#blog_entry_situation", Input).clear()
self.query_one("#blog_entry_container", ScrollableContainer).refresh()
self.query_one("#blog_input_container", ScrollableContainer).refresh()
return

@on(Input.Changed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self, selected_item: str = "", *args, **kwargs):

def compose(self) -> ComposeResult:
yield Header(show_clock=True)
yield Static(classes="empty")
yield ScrollableContainer(
Static(f"Please provide the following input as appropriate:"),
Static("Display Name should be short but descriptive, it will also be used to create the Qualified Name as well"),
Expand Down
141 changes: 141 additions & 0 deletions my_egeria/my_egeria/DemoCode/My_Profile/FeedbackScreens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""
PDX-License-Identifier: Apache-2.0
Copyright Contributors to the ODPi Egeria project.

This file provides the screens for the app-wide feedback mechanism in my_egeria:
a form to leave feedback from any screen, and a viewer for the private feedback
note log (see feedback_handler.py for the Egeria side).

"""
from typing import Any

from textual import on
from textual.app import ComposeResult
from textual.containers import ScrollableContainer, Horizontal
from textual.screen import ModalScreen
from textual.widgets import Header, Static, Footer, Button, DataTable, Select, TextArea

FEEDBACK_CATEGORIES = ["Bug", "Suggestion", "Question", "Praise", "Other"]


class FeedbackScreen(ModalScreen):
""" Collect feedback about the screen the user was on when they pressed the feedback key """

BINDINGS = [
("ctrl+s", "submit", "Submit Feedback"),
("escape", "cancel", "Cancel"),
]

CSS_PATH = "my_profile.tcss"

def __init__(self, screen_name: str, screen_title: str = "", *args, **kwargs):
super().__init__(*args, **kwargs)
self.screen_name = screen_name
self.screen_title = screen_title
self.category = FEEDBACK_CATEGORIES[1]

def on_mount(self):
self.title = "Egeria - My Profile"
self.sub_title = "Leave Feedback"
self.query_one("#feedback_text", TextArea).focus()

def compose(self) -> ComposeResult:
"""This method composes the UI for the FeedbackScreen."""
context = self.screen_name if not self.screen_title else f"{self.screen_name} ({self.screen_title})"
yield Header(show_clock=True)
yield Static("Leave Feedback", classes="span-3", id="feedback_title")
yield ScrollableContainer(
Static(f"[b]Feedback on:[/b] {context}"),
Static("Category"),
Select(
[(category, category) for category in FEEDBACK_CATEGORIES],
value=self.category,
allow_blank=False,
id="feedback_category",
),
Static("Feedback"),
TextArea(id="feedback_text"),
Static("Your feedback is recorded in a private feedback log. Use Cancel to return to the previous screen"),
Horizontal(
Button("Submit", id="submit_feedback_button", variant="primary"),
Button("Cancel", id="cancel_feedback_button", variant="warning"),
),
id="feedback_container",
)
yield Footer()

@on(Select.Changed, "#feedback_category")
def handle_category_changed(self, event: Select.Changed):
self.category = str(event.value)

def action_submit(self):
feedback_text = self.query_one("#feedback_text", TextArea).text.strip()
if not feedback_text:
self.notify("Please enter some feedback before submitting", timeout=5, severity="warning")
return
feedback_data = {
"screen": self.screen_name,
"screen_title": self.screen_title,
"category": self.category,
"text": feedback_text,
}
self.log(f"Feedback data: {feedback_data} being returned from screen")
self.dismiss(feedback_data)

def action_cancel(self):
self.dismiss(None)

@on(Button.Pressed, "#submit_feedback_button")
def handle_submit_button(self):
self.action_submit()

@on(Button.Pressed, "#cancel_feedback_button")
def handle_cancel_button(self):
self.action_cancel()


class FeedbackLogScreen(ModalScreen):
""" Show the accumulated entries in the private feedback note log """

BINDINGS = [
("q", "quit", "Quit"),
("escape", "quit", "Back"),
]

CSS_PATH = "my_profile.tcss"

def __init__(self, feedback_entries: list[dict[str, Any]], *args, **kwargs):
super().__init__(*args, **kwargs)
self.feedback_entries = feedback_entries or []

def on_mount(self):
self.title = "Egeria - My Profile"
self.sub_title = f"Feedback Log ({len(self.feedback_entries)} entries)"
table = self.query_one("#feedback_log_table", DataTable)
table.add_columns("Date", "Submitted By", "Category", "Screen", "Feedback")
table.zebra_stripes = True
table.cursor_type = "row"
if not self.feedback_entries:
table.add_row("", "", "", "", "No feedback has been recorded yet")
for entry in self.feedback_entries:
table.add_row(
str(entry.get("date", "")),
str(entry.get("submitted_by", "")),
str(entry.get("category", "")),
str(entry.get("screen", "")),
str(entry.get("text", "")),
)
table.focus()

def compose(self) -> ComposeResult:
"""This method composes the UI for the FeedbackLogScreen."""
yield Header(show_clock=True)
yield Static("Feedback Log", classes="span-3", id="feedback_log_title")
yield ScrollableContainer(
DataTable(id="feedback_log_table"),
id="feedback_log_container",
)
yield Footer()

def action_quit(self):
self.dismiss(200)
20 changes: 20 additions & 0 deletions my_egeria/my_egeria/DemoCode/My_Profile/MainScreen.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class MainScreen(Screen):

BINDINGS = [
("q", "app.quit", "Quit"),
("ctrl+a", "add_comment","add comment to selected row"),
("ctrl+b", "bookmarks", "Manage Bookmarks"),
("ctrl+s", "show_comments", "Show Comments for Selected Row"),
("ctrl+t", "edit_table", "Edit Selected Table"),
Expand Down Expand Up @@ -58,6 +59,8 @@ def compose(self) -> ComposeResult:
Option("[] Subscriptions"),
Option("[] Technology Types"),
Option("[] User Bookmarks"),
Option("[] Leave Feedback"),
Option("[] Feedback Log"),
id="other_function_list"
),
id="other_function_container"
Expand Down Expand Up @@ -181,6 +184,23 @@ async def action_show_comments(self):
else:
self.notify("Please select a row and table to show comments.", timeout=5, severity="warning")

async def action_add_comment(self):
""" Add a comment to the selected table and row """
table_name, row_k = self.get_current_table_and_row()
if table_name and row_k:
self.selected_table = table_name
self.selected_row = row_k
add_comment_return = self.app.add_comment(table_name, row_k)
if add_comment_return:
if add_comment_return == 200:
self.log("Successfully added comment")
return
else:
self.log("Failed to add comment.")
self.notify("Failed to add comment.", timeout=20, severity="error")
else:
self.notify("Please select a row and table to add a comment.", timeout=5, severity="warning")

async def action_add_to_table(self):
""" Add to the selected table.

Expand Down
2 changes: 2 additions & 0 deletions my_egeria/my_egeria/DemoCode/My_Profile/RETURN_CODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ In accordance with application conventions:
| **`422`** | `DATA_SPECIFICATION_RETRIEVAL_ERROR` | Error retrieving data specification details from Egeria in Shop for Data handler. | `shop_for_data_handler.py` |
| **`423`** | `BUSINESS_DOMAIN_SPEC_ERROR` | Error executing BusinessCapabilities report specification in Shop for Data handler. | `shop_for_data_handler.py` |
| **`429`** | `SAMPLE_DATA_RETRIEVAL_ERROR` | Failed to retrieve or parse sample data from Egeria Asset Catalog / Data Engine in Shop for Data handler. | `shop_for_data_handler.py` |
| **`430`** | `INCOMPATIBLE_ENVIRONMENT` | App started under a Python whose pydantic is older than pyegeria requires, so request bodies would reach Egeria with their parameters silently missing. The app exits at startup with a message naming the interpreter and how to run from the project venv instead. | `my_profile_app.py`, `profile_utils.py` |
| **`440`** | `TEAM_ROLES_OR_GLOSSARY_ERROR` | Error communicating with Egeria or retrieving team members, user roles, or glossary term details. | `team_roles_handler.py` |

---
Expand All @@ -57,4 +58,5 @@ In accordance with application conventions:
- **400–409**: Screen UI widget creation, mount, and fallback recovery errors.
- **410–419**: Tree resolution errors in selection overview, and technology type data extraction / callback payload errors.
- **420–429**: Data retrieval exceptions, report specification execution failures, and template instantiation failures across Shop for Data and Technology Types.
- **430**: Incompatible Python environment detected at startup.
- **440**: Team roles and glossary term query communication errors.
89 changes: 0 additions & 89 deletions my_egeria/my_egeria/DemoCode/My_Profile/ShowCommentScreen.py

This file was deleted.

Loading
Loading