feat: Add --new flag to UI with prefill options for title, template, participants, context
Opens new discussion dialog on launch with optional pre-filled values. Enables integration with development-hub for launching discussions from todos. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8d8958ff79
commit
d71b837c16
|
|
@ -372,6 +372,15 @@ def cmd_ui(args) -> int:
|
||||||
else:
|
else:
|
||||||
directory = path
|
directory = path
|
||||||
|
|
||||||
|
# Parse prefill options
|
||||||
|
show_new = getattr(args, 'new', False)
|
||||||
|
prefill_title = getattr(args, 'title', None)
|
||||||
|
prefill_template = getattr(args, 'template', None)
|
||||||
|
prefill_context = getattr(args, 'context', None)
|
||||||
|
prefill_participants = None
|
||||||
|
if getattr(args, 'participants', None):
|
||||||
|
prefill_participants = [p.strip().lstrip('@') for p in args.participants.split(',')]
|
||||||
|
|
||||||
if args.tui:
|
if args.tui:
|
||||||
# Launch TUI (urwid-based)
|
# Launch TUI (urwid-based)
|
||||||
try:
|
try:
|
||||||
|
|
@ -380,6 +389,7 @@ def cmd_ui(args) -> int:
|
||||||
print("Error: TUI requires urwid. Install with: pip install urwid")
|
print("Error: TUI requires urwid. Install with: pip install urwid")
|
||||||
print(f"Details: {e}")
|
print(f"Details: {e}")
|
||||||
return 1
|
return 1
|
||||||
|
# TUI doesn't support --new yet, just launch normally
|
||||||
tui_main(directory, open_file=open_file)
|
tui_main(directory, open_file=open_file)
|
||||||
else:
|
else:
|
||||||
# Launch GUI (Dear PyGui-based)
|
# Launch GUI (Dear PyGui-based)
|
||||||
|
|
@ -395,7 +405,15 @@ def cmd_ui(args) -> int:
|
||||||
print(f"TUI also unavailable: {e2}")
|
print(f"TUI also unavailable: {e2}")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
gui_main(directory, open_file=open_file)
|
gui_main(
|
||||||
|
directory,
|
||||||
|
open_file=open_file,
|
||||||
|
show_new_dialog=show_new,
|
||||||
|
prefill_title=prefill_title,
|
||||||
|
prefill_template=prefill_template,
|
||||||
|
prefill_participants=prefill_participants,
|
||||||
|
prefill_context=prefill_context,
|
||||||
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -461,6 +479,11 @@ def main(argv: list[str] = None) -> int:
|
||||||
p_ui = subparsers.add_parser("ui", help="Launch interactive UI")
|
p_ui = subparsers.add_parser("ui", help="Launch interactive UI")
|
||||||
p_ui.add_argument("path", nargs="?", help="Discussion file (.md) or directory to browse")
|
p_ui.add_argument("path", nargs="?", help="Discussion file (.md) or directory to browse")
|
||||||
p_ui.add_argument("--tui", action="store_true", help="Use terminal UI instead of graphical UI")
|
p_ui.add_argument("--tui", action="store_true", help="Use terminal UI instead of graphical UI")
|
||||||
|
p_ui.add_argument("--new", "-n", action="store_true", help="Open new discussion dialog on launch")
|
||||||
|
p_ui.add_argument("--title", help="Pre-fill title in new discussion dialog (requires --new)")
|
||||||
|
p_ui.add_argument("--template", help="Pre-select template in new discussion dialog (requires --new)")
|
||||||
|
p_ui.add_argument("--participants", help="Pre-select participants, comma-separated (requires --new)")
|
||||||
|
p_ui.add_argument("--context", help="Pre-fill context/description in new discussion dialog (requires --new)")
|
||||||
p_ui.set_defaults(func=cmd_ui)
|
p_ui.set_defaults(func=cmd_ui)
|
||||||
|
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
|
||||||
|
|
@ -2454,8 +2454,16 @@ class DiscussionGUI:
|
||||||
("pragmatist", "AI-Pragmatist")
|
("pragmatist", "AI-Pragmatist")
|
||||||
]
|
]
|
||||||
|
|
||||||
def _show_new_discussion_dialog(self):
|
def _show_new_discussion_dialog(self, prefill_title: str = None, prefill_template: str = None,
|
||||||
"""Show dialog for creating a new discussion."""
|
prefill_participants: list[str] = None, prefill_context: str = None):
|
||||||
|
"""Show dialog for creating a new discussion.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prefill_title: Pre-fill title field
|
||||||
|
prefill_template: Pre-select template
|
||||||
|
prefill_participants: Pre-select participants (list of aliases)
|
||||||
|
prefill_context: Pre-fill context/description field
|
||||||
|
"""
|
||||||
window_tag = "new_discussion_dialog"
|
window_tag = "new_discussion_dialog"
|
||||||
if dpg.does_item_exist(window_tag):
|
if dpg.does_item_exist(window_tag):
|
||||||
dpg.delete_item(window_tag)
|
dpg.delete_item(window_tag)
|
||||||
|
|
@ -2463,9 +2471,10 @@ class DiscussionGUI:
|
||||||
templates = self._get_templates()
|
templates = self._get_templates()
|
||||||
participants = self._get_participants()
|
participants = self._get_participants()
|
||||||
|
|
||||||
# State for the dialog
|
# State for the dialog - use prefill if provided, otherwise defaults
|
||||||
|
default_participants = prefill_participants if prefill_participants else ["architect", "security", "pragmatist"]
|
||||||
dialog_state = {
|
dialog_state = {
|
||||||
'selected_participants': ["architect", "security", "pragmatist"],
|
'selected_participants': list(default_participants),
|
||||||
}
|
}
|
||||||
|
|
||||||
def toggle_participant(sender, app_data, user_data):
|
def toggle_participant(sender, app_data, user_data):
|
||||||
|
|
@ -2545,7 +2554,8 @@ class DiscussionGUI:
|
||||||
width=550, height=550, pos=[400, 150], no_collapse=True):
|
width=550, height=550, pos=[400, 150], no_collapse=True):
|
||||||
|
|
||||||
dpg.add_text("Title:", color=(150, 200, 255))
|
dpg.add_text("Title:", color=(150, 200, 255))
|
||||||
dpg.add_input_text(tag="new_disc_title", width=-1, hint="Enter discussion title")
|
dpg.add_input_text(tag="new_disc_title", width=-1, hint="Enter discussion title",
|
||||||
|
default_value=prefill_title or "")
|
||||||
|
|
||||||
dpg.add_spacer(height=5)
|
dpg.add_spacer(height=5)
|
||||||
dpg.add_text("Location:", color=(150, 200, 255))
|
dpg.add_text("Location:", color=(150, 200, 255))
|
||||||
|
|
@ -2561,10 +2571,15 @@ class DiscussionGUI:
|
||||||
dpg.add_spacer(height=10)
|
dpg.add_spacer(height=10)
|
||||||
dpg.add_text("Template:", color=(150, 200, 255))
|
dpg.add_text("Template:", color=(150, 200, 255))
|
||||||
template_items = templates + ["+ Create New Template..."]
|
template_items = templates + ["+ Create New Template..."]
|
||||||
|
# Use prefill template if valid, otherwise first template or 'feature'
|
||||||
|
if prefill_template and prefill_template in templates:
|
||||||
|
default_template = prefill_template
|
||||||
|
else:
|
||||||
|
default_template = templates[0] if templates else "feature"
|
||||||
dpg.add_combo(
|
dpg.add_combo(
|
||||||
items=template_items,
|
items=template_items,
|
||||||
tag="new_disc_template",
|
tag="new_disc_template",
|
||||||
default_value=templates[0] if templates else "feature",
|
default_value=default_template,
|
||||||
width=-1,
|
width=-1,
|
||||||
callback=on_template_change
|
callback=on_template_change
|
||||||
)
|
)
|
||||||
|
|
@ -2582,10 +2597,10 @@ class DiscussionGUI:
|
||||||
|
|
||||||
with dpg.child_window(height=150, border=True):
|
with dpg.child_window(height=150, border=True):
|
||||||
for alias, display_name in participants:
|
for alias, display_name in participants:
|
||||||
is_default = alias in ["architect", "security", "pragmatist"]
|
is_selected = alias in dialog_state['selected_participants']
|
||||||
dpg.add_checkbox(
|
dpg.add_checkbox(
|
||||||
label=f"@{alias} ({display_name})",
|
label=f"@{alias} ({display_name})",
|
||||||
default_value=is_default,
|
default_value=is_selected,
|
||||||
callback=toggle_participant,
|
callback=toggle_participant,
|
||||||
user_data=alias
|
user_data=alias
|
||||||
)
|
)
|
||||||
|
|
@ -2597,7 +2612,8 @@ class DiscussionGUI:
|
||||||
multiline=True,
|
multiline=True,
|
||||||
width=-1,
|
width=-1,
|
||||||
height=100,
|
height=100,
|
||||||
hint="Describe what this discussion is about..."
|
hint="Describe what this discussion is about...",
|
||||||
|
default_value=prefill_context or ""
|
||||||
)
|
)
|
||||||
|
|
||||||
dpg.add_spacer(height=15)
|
dpg.add_spacer(height=15)
|
||||||
|
|
@ -4139,6 +4155,17 @@ final = json.dumps(parsed)''',
|
||||||
self._open_discussion(self._pending_open_file)
|
self._open_discussion(self._pending_open_file)
|
||||||
self._pending_open_file = None
|
self._pending_open_file = None
|
||||||
|
|
||||||
|
# Show new discussion dialog if requested
|
||||||
|
if getattr(self, '_pending_new_dialog', None):
|
||||||
|
prefill = self._pending_new_dialog
|
||||||
|
self._show_new_discussion_dialog(
|
||||||
|
prefill_title=prefill.get('title'),
|
||||||
|
prefill_template=prefill.get('template'),
|
||||||
|
prefill_participants=prefill.get('participants'),
|
||||||
|
prefill_context=prefill.get('context'),
|
||||||
|
)
|
||||||
|
self._pending_new_dialog = None
|
||||||
|
|
||||||
# Manual render loop with background task polling
|
# Manual render loop with background task polling
|
||||||
while dpg.is_dearpygui_running():
|
while dpg.is_dearpygui_running():
|
||||||
# Poll for updates from background threads (output, turn completion)
|
# Poll for updates from background threads (output, turn completion)
|
||||||
|
|
@ -4150,12 +4177,19 @@ final = json.dumps(parsed)''',
|
||||||
dpg.destroy_context()
|
dpg.destroy_context()
|
||||||
|
|
||||||
|
|
||||||
def main(discussions_dir: str = None, open_file: str = None):
|
def main(discussions_dir: str = None, open_file: str = None, show_new_dialog: bool = False,
|
||||||
|
prefill_title: str = None, prefill_template: str = None,
|
||||||
|
prefill_participants: list[str] = None, prefill_context: str = None):
|
||||||
"""Entry point for GUI.
|
"""Entry point for GUI.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
discussions_dir: Directory to browse for discussions
|
discussions_dir: Directory to browse for discussions
|
||||||
open_file: Specific discussion file to open immediately
|
open_file: Specific discussion file to open immediately
|
||||||
|
show_new_dialog: Show new discussion dialog on launch
|
||||||
|
prefill_title: Pre-fill title in new discussion dialog
|
||||||
|
prefill_template: Pre-select template in new discussion dialog
|
||||||
|
prefill_participants: Pre-select participants in new discussion dialog
|
||||||
|
prefill_context: Pre-fill context in new discussion dialog
|
||||||
"""
|
"""
|
||||||
dir_path = Path(discussions_dir) if discussions_dir else None
|
dir_path = Path(discussions_dir) if discussions_dir else None
|
||||||
app = DiscussionGUI(dir_path)
|
app = DiscussionGUI(dir_path)
|
||||||
|
|
@ -4166,6 +4200,17 @@ def main(discussions_dir: str = None, open_file: str = None):
|
||||||
else:
|
else:
|
||||||
app._pending_open_file = None
|
app._pending_open_file = None
|
||||||
|
|
||||||
|
# If new dialog was requested, store prefill data
|
||||||
|
if show_new_dialog:
|
||||||
|
app._pending_new_dialog = {
|
||||||
|
'title': prefill_title,
|
||||||
|
'template': prefill_template,
|
||||||
|
'participants': prefill_participants,
|
||||||
|
'context': prefill_context,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
app._pending_new_dialog = None
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue