Private
Public Access
reading more code, slight adjustment to ast structual file editor ux (radio buttons going off viewport)
This commit is contained in:
+111
-128
@@ -147,9 +147,9 @@ def C_NUM() -> imgui.ImVec4: return theme.get_color("status_success")
|
||||
def C_TRM() -> imgui.ImVec4: return theme.get_color("text_disabled")
|
||||
def C_SUB() -> imgui.ImVec4: return theme.get_color("text_disabled")
|
||||
|
||||
DIR_COLORS: dict[str, typing.Callable[[], imgui.ImVec4]] = {"OUT": C_OUT, "IN": C_IN}
|
||||
DIR_COLORS: dict[str, typing.Callable[[], imgui.ImVec4]] = {"OUT": C_OUT, "IN": C_IN}
|
||||
KIND_COLORS: dict[str, typing.Callable[[], imgui.ImVec4]] = {"request": C_REQ, "response": C_RES, "tool_call": C_TC, "tool_result": C_TR, "tool_result_send": C_TRS}
|
||||
HEAVY_KEYS: set[str] = {"message", "text", "script", "output", "content"}
|
||||
HEAVY_KEYS: set[str] = {"message", "text", "script", "output", "content"}
|
||||
|
||||
def render_text_viewer(app: App, label: str, content: str, text_type: str = 'text', force_open: bool = False, id_suffix: str = "") -> None:
|
||||
if imgui.button(f"[+]##{id_suffix or str(id(content))}") or force_open:
|
||||
@@ -3579,13 +3579,11 @@ def render_context_composition_panel(app: App) -> None:
|
||||
render_context_screenshots(app)
|
||||
|
||||
def render_ast_inspector_modal(app: App) -> None:
|
||||
"""
|
||||
Renders the 'Structural File Editor' modal dialog.
|
||||
"""Renders the 'Structural File Editor' modal dialog.
|
||||
Provides an interactive tree-sitter AST inspector to mask classes, methods, or
|
||||
functions and extract custom annotated slices (Definition, Signature, Hide).
|
||||
|
||||
SSDL Shape:
|
||||
`[B:open_modal?] -> [Q:outline] -> [I:render_ast_tree]`
|
||||
SSDL: `[B:open_modal?] -> [Q:outline] -> [I:render_ast_tree]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+-------------------------------------------------------------+
|
||||
@@ -3622,14 +3620,14 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
proj_dir = str(Path(app.controller.active_project_path).parent.resolve()) if getattr(app, 'controller', None) and app.controller.active_project_path else None
|
||||
mcp_client.configure([{"path": f_path}], [proj_dir] if proj_dir else None)
|
||||
|
||||
if f_path.lower().endswith('.py'): outline = mcp_client.py_get_code_outline(f_path)
|
||||
elif f_path.lower().endswith(('.c', '.h')): outline = mcp_client.ts_c_get_code_outline(f_path)
|
||||
if f_path.lower().endswith('.py'): outline = mcp_client.py_get_code_outline(f_path)
|
||||
elif f_path.lower().endswith(('.c', '.h')): outline = mcp_client.ts_c_get_code_outline(f_path)
|
||||
elif f_path.lower().endswith(('.cpp', '.hpp', '.cxx', '.cc')): outline = mcp_client.ts_cpp_get_code_outline(f_path)
|
||||
except Exception as e:
|
||||
outline = f"Error fetching outline: {e}"
|
||||
|
||||
app._cached_ast_nodes = []
|
||||
import re
|
||||
import re #TODO(Ed): Review local import
|
||||
pattern = re.compile(r'^(\s*)\[(.*?)\] (.*?) \(Lines (\d+)-(\d+)\)')
|
||||
stack = [] # (indent, name)
|
||||
for line in outline.splitlines():
|
||||
@@ -3671,74 +3669,83 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
|
||||
# --- LEFT COLUMN: AST Tree & Slice Management ---
|
||||
imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 0), True)
|
||||
if True:
|
||||
if imgui.collapsing_header("AST Tree", imgui.TreeNodeFlags_.default_open):
|
||||
if not getattr(app, '_cached_ast_nodes', None): imgui.text("No AST nodes found.")
|
||||
else:
|
||||
# if True:
|
||||
if imgui.collapsing_header("AST Tree", imgui.TreeNodeFlags_.default_open):
|
||||
if not getattr(app, '_cached_ast_nodes', None): imgui.text("No AST nodes found.")
|
||||
else:
|
||||
with imscope.table('ast tree members', 2, imgui.TableFlags_.resizable | imgui.TableFlags_.sizing_stretch_prop)
|
||||
imgui.table_setup_column("symbol", imgui.TableColumnFlags_.width_fixed, 400)
|
||||
imgui.table_setup_column("option", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
for node in app._cached_ast_nodes:
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
indent = node['indent']
|
||||
kind = node['kind']
|
||||
name = node['name']
|
||||
full_path = node['full_path']
|
||||
|
||||
|
||||
imgui.dummy(imgui.ImVec2(indent * 10, 0))
|
||||
imgui.same_line()
|
||||
imgui.text(f"[{kind}] {name}")
|
||||
|
||||
|
||||
if imgui.is_item_hovered():
|
||||
app._hovered_ast_node = full_path
|
||||
|
||||
btn_width = 150
|
||||
avail_width = imgui.get_content_region_avail().x
|
||||
do_align = avail_width > btn_width if isinstance(avail_width, (int, float)) else False
|
||||
if do_align: imgui.same_line(imgui.get_window_width() - btn_width)
|
||||
else: imgui.same_line()
|
||||
imgui.table_next_column()
|
||||
|
||||
# btn_width = 150
|
||||
# avail_width = imgui.get_content_region_avail().x
|
||||
# do_align = avail_width > btn_width if isinstance(avail_width, (int, float)) else False
|
||||
# if do_align: imgui.same_line((avail_width - btn_width))
|
||||
# else: imgui.same_line()
|
||||
# imgui.same_line((avail_width - btn_width) * 0.925)
|
||||
|
||||
if not hasattr(f_item, 'ast_mask'): f_item.ast_mask = {}
|
||||
current_mode = f_item.ast_mask.get(full_path, 'hide')
|
||||
|
||||
|
||||
imgui.push_id(full_path)
|
||||
if imgui.radio_button("Def", current_mode == 'def'): f_item.ast_mask[full_path] = 'def'
|
||||
if imgui.radio_button("Def", current_mode == 'def'): f_item.ast_mask[full_path] = 'def'
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Sig", current_mode == 'sig'): f_item.ast_mask[full_path] = 'sig'
|
||||
if imgui.radio_button("Sig", current_mode == 'sig'): f_item.ast_mask[full_path] = 'sig'
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Hide", current_mode == 'hide'): f_item.ast_mask[full_path] = 'hide'
|
||||
imgui.pop_id()
|
||||
|
||||
imgui.separator()
|
||||
if imgui.collapsing_header("Custom Slices", imgui.TreeNodeFlags_.default_open):
|
||||
if not hasattr(f_item, 'custom_slices'): f_item.custom_slices = []
|
||||
imgui.text_colored(C_IN(), "Highlight lines in right pane to add slices.")
|
||||
if imgui.button("Add Selection as Slice"):
|
||||
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
|
||||
s_line = min(app._slice_sel_start, app._slice_sel_end)
|
||||
e_line = max(app._slice_sel_start, app._slice_sel_end)
|
||||
from src.fuzzy_anchor import FuzzyAnchor
|
||||
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
|
||||
slice_data['tag'] = ""; slice_data['comment'] = ""
|
||||
f_item.custom_slices.append(slice_data)
|
||||
app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
|
||||
imgui.separator()
|
||||
if imgui.collapsing_header("Custom Slices", imgui.TreeNodeFlags_.default_open):
|
||||
if not hasattr(f_item, 'custom_slices'): f_item.custom_slices = []
|
||||
imgui.text_colored(C_IN(), "Highlight lines in right pane to add slices.")
|
||||
if imgui.button("Add Selection as Slice"):
|
||||
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
|
||||
s_line = min(app._slice_sel_start, app._slice_sel_end)
|
||||
e_line = max(app._slice_sel_start, app._slice_sel_end)
|
||||
from src.fuzzy_anchor import FuzzyAnchor
|
||||
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
|
||||
slice_data['tag'] = ""; slice_data['comment'] = ""
|
||||
f_item.custom_slices.append(slice_data)
|
||||
app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear Selection"): app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Auto-Populate"): app._populate_auto_slices(f_item)
|
||||
|
||||
to_remove = -1
|
||||
tags = app.controller.project.get("context_tags", ["auto-ast", "bug", "feature", "important"])
|
||||
for idx, slc in enumerate(f_item.custom_slices):
|
||||
imgui.push_id(f"slc_row_{idx}"); imgui.text(f"#{idx+1}: L{slc['start_line']}-{slc['end_line']}"); imgui.same_line()
|
||||
current_tag = slc.get('tag', '')
|
||||
if current_tag not in tags and current_tag: tags.append(current_tag)
|
||||
tag_idx = tags.index(current_tag) if current_tag in tags else 0
|
||||
imgui.set_next_item_width(100)
|
||||
ch_tag, new_tag_idx = imgui.combo("##Tag", tag_idx, tags)
|
||||
if ch_tag: slc['tag'] = tags[new_tag_idx]
|
||||
imgui.same_line(); imgui.set_next_item_width(-30); changed_comm, new_comm = imgui.input_text("##Note", slc.get('comment', ''))
|
||||
if changed_comm: slc['comment'] = new_comm
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear Selection"): app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Auto-Populate"): app._populate_auto_slices(f_item)
|
||||
|
||||
to_remove = -1
|
||||
tags = app.controller.project.get("context_tags", ["auto-ast", "bug", "feature", "important"])
|
||||
for idx, slc in enumerate(f_item.custom_slices):
|
||||
imgui.push_id(f"slc_row_{idx}"); imgui.text(f"#{idx+1}: L{slc['start_line']}-{slc['end_line']}"); imgui.same_line()
|
||||
current_tag = slc.get('tag', '')
|
||||
if current_tag not in tags and current_tag: tags.append(current_tag)
|
||||
tag_idx = tags.index(current_tag) if current_tag in tags else 0
|
||||
imgui.set_next_item_width(100)
|
||||
ch_tag, new_tag_idx = imgui.combo("##Tag", tag_idx, tags)
|
||||
if ch_tag: slc['tag'] = tags[new_tag_idx]
|
||||
imgui.same_line(); imgui.set_next_item_width(-30); changed_comm, new_comm = imgui.input_text("##Note", slc.get('comment', ''))
|
||||
if changed_comm: slc['comment'] = new_comm
|
||||
imgui.same_line()
|
||||
if imgui.button("X"): to_remove = idx
|
||||
imgui.pop_id()
|
||||
if to_remove != -1: f_item.custom_slices.pop(to_remove)
|
||||
if imgui.button("X"): to_remove = idx
|
||||
imgui.pop_id()
|
||||
if to_remove != -1: f_item.custom_slices.pop(to_remove)
|
||||
imgui.end_child()
|
||||
|
||||
imgui.table_next_column()
|
||||
@@ -6275,11 +6282,9 @@ def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") -
|
||||
#region: MMA
|
||||
|
||||
def render_mma_dashboard(app: App) -> None:
|
||||
"""
|
||||
Main MMA dashboard interface.
|
||||
"""Main MMA dashboard interface.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:focus_selector] -> [I:track_summary] -> [B:epic_planner] -> [I:track_browser] -> [B:global_controls] -> [I:usage_analytics] -> [I:ticket_queue] -> [I:task_dag] => [I:agent_streams]`
|
||||
SSDL: `[I:focus_selector] -> [I:track_summary] -> [B:epic_planner] -> [I:track_browser] -> [B:global_controls] -> [I:usage_analytics] -> [I:ticket_queue] -> [I:task_dag] => [I:agent_streams]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6325,13 +6330,11 @@ def render_mma_dashboard(app: App) -> None:
|
||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_mma_dashboard")
|
||||
|
||||
def render_mma_modals(app: App) -> None:
|
||||
"""
|
||||
Renders all MMA-specific approval and info modals: Tool Execution Approval,
|
||||
"""Renders all MMA-specific approval and info modals: Tool Execution Approval,
|
||||
MMA Step Approval (with optional payload edit), MMA Spawn Approval (with
|
||||
prompt/context editing), and the Cycle Detected error modal.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:pending_queues] => [I:tool_approval_modal] | [I:step_approval_modal] | [I:spawn_approval_modal] | [I:cycle_modal]`
|
||||
SSDL: `[I:pending_queues] => [I:tool_approval_modal] | [I:step_approval_modal] | [I:spawn_approval_modal] | [I:cycle_modal]`
|
||||
|
||||
ASCII Layout Map:
|
||||
Conditionally opens (at most one at a time):
|
||||
@@ -6426,13 +6429,11 @@ def render_mma_modals(app: App) -> None:
|
||||
imgui.end_popup()
|
||||
|
||||
def render_mma_track_summary(app: App) -> None:
|
||||
"""
|
||||
Renders the active-track summary row: track name, MMA pipeline status, and running
|
||||
"""Renders the active-track summary row: track name, MMA pipeline status, and running
|
||||
cost estimate, followed by a colour-coded progress bar and a 4-column breakdown table
|
||||
(Completed / In Progress / Blocked / Todo) and ETA estimation.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:track_name] -> [I:status_badge] -> [I:cost] -> [I:progress_bar] -> [I:stats_table] -> [I:eta]`
|
||||
SSDL: `[I:track_name] -> [I:status_badge] -> [I:cost] -> [I:progress_bar] -> [I:stats_table] -> [I:eta]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6470,11 +6471,9 @@ def render_mma_track_summary(app: App) -> None:
|
||||
imgui.text_colored(C_LBL(), "ETA:"); imgui.same_line(); imgui.text_colored(C_VAL(), f"~{int(eta_mins)}m ({remaining} tickets remaining)")
|
||||
|
||||
def render_mma_epic_planner(app: App) -> None:
|
||||
"""
|
||||
Renders the Epic Planning panel for Tier 1 strategy input and planning button.
|
||||
"""Renders the Epic Planning panel for Tier 1 strategy input and planning button.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:input_textbox] => [B:plan_button]`
|
||||
SSDL: `[I:input_textbox] => [B:plan_button]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6482,7 +6481,7 @@ def render_mma_epic_planner(app: App) -> None:
|
||||
| +-----------------------------------------------------+ |
|
||||
| | Describe the epic goal... | |
|
||||
| +-----------------------------------------------------+ |
|
||||
| [Plan Epic (Tier 1) ] |
|
||||
| [Plan Epic (Tier 1) ] |
|
||||
+---------------------------------------------------------+
|
||||
"""
|
||||
imgui.text_colored(C_LBL(), 'Epic Planning (Tier 1)')
|
||||
@@ -6490,12 +6489,10 @@ def render_mma_epic_planner(app: App) -> None:
|
||||
if imgui.button('Plan Epic (Tier 1)', imgui.ImVec2(-1, 0)): app._cb_plan_epic()
|
||||
|
||||
def render_mma_conductor_setup(app: App) -> None:
|
||||
"""
|
||||
Renders the Conductor Setup panel. Runs a one-shot project-structure scan and
|
||||
"""Renders the Conductor Setup panel. Runs a one-shot project-structure scan and
|
||||
shows the summarised output in a read-only text area.
|
||||
|
||||
SSDL Shape:
|
||||
`[B:run_scan] => [I:summary_text]`
|
||||
SSDL: `[B:run_scan] => [I:summary_text]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6511,22 +6508,20 @@ def render_mma_conductor_setup(app: App) -> None:
|
||||
if app.ui_conductor_setup_summary: imgui.input_text_multiline("##setup_summary", app.ui_conductor_setup_summary, imgui.ImVec2(-1, 120), imgui.InputTextFlags_.read_only)
|
||||
|
||||
def render_mma_track_browser(app: App) -> None:
|
||||
"""
|
||||
Renders the Track Browser: a table listing all known tracks with status, progress bar,
|
||||
"""Renders the Track Browser: a table listing all known tracks with status, progress bar,
|
||||
and a [Load] button per row. Below the table is a form for creating a new track.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:tracks_table] -> [B:load_button] -> [I:create_track_form] => [B:create_track]`
|
||||
SSDL: `[I:tracks_table] -> [B:load_button] -> [I:create_track_form] => [B:create_track]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
| Track Browser |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| | Title | Status | Progress | Actions | |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| | my-feature-0612 | ACTIVE | [===== ] [Load] | |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| | Title | Status | Progress | Actions | |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| | my-feature-0612 | ACTIVE | [===== ] [Load] | |
|
||||
| | chore-cleanup | NEW | [ ] [Load] | |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| +------------------+--------+----------+---------+ |
|
||||
| Create New Track |
|
||||
| Name: [___________] |
|
||||
| Description: [_____________________________] |
|
||||
@@ -6560,13 +6555,11 @@ def render_mma_track_browser(app: App) -> None:
|
||||
app.ui_new_track_name = ""; app.ui_new_track_desc = ""
|
||||
|
||||
def render_mma_global_controls(app: App) -> None:
|
||||
"""
|
||||
Renders the MMA global controls bar: Step Mode (HITL) toggle, pipeline status label,
|
||||
"""Renders the MMA global controls bar: Step Mode (HITL) toggle, pipeline status label,
|
||||
Pause/Resume engine button, active tier badge, approval-pending blink indicator, and
|
||||
the Hot Reload shortcut.
|
||||
|
||||
SSDL Shape:
|
||||
`[B:step_mode] -> [I:status] -> [B:pause_resume] -> [I:active_tier] -> [I:approval_blink] -> [B:hot_reload]`
|
||||
SSDL: `[B:step_mode] -> [I:status] -> [B:pause_resume] -> [I:active_tier] -> [I:approval_blink] -> [B:hot_reload]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6604,25 +6597,23 @@ def render_mma_global_controls(app: App) -> None:
|
||||
imgui.same_line(); imgui.text_disabled("(Ctrl+Alt+R)")
|
||||
|
||||
def render_mma_usage_section(app: App) -> None:
|
||||
"""
|
||||
Renders the Tier Usage table (tokens and estimated cost per tier) and, when expanded,
|
||||
"""Renders the Tier Usage table (tokens and estimated cost per tier) and, when expanded,
|
||||
a collapsible Tier Model Config section with per-tier provider, model, tool-preset,
|
||||
and persona overrides.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:usage_table] -> [B:tier_model_config_header] => [I:combos_per_tier]`
|
||||
SSDL: `[I:usage_table] -> [B:tier_model_config_header] => [I:combos_per_tier]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
| Tier Usage (Tokens & Cost) |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| | Tier | Model | Input | Output | Cost | |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| | Tier 1 | gemini-2.5-flash | 1,200 | 400 | $0.001 | |
|
||||
| | TOTAL | | | | $0.004 | |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| | Tier | Model | Input | Output | Cost | |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| | Tier 1 | gemini-2.5-flash | 1,200 | 400 | $0.001 | |
|
||||
| | TOTAL | | | | $0.004 | |
|
||||
| +--------+------------------+-------+-------+--------+ |
|
||||
| > Tier Model Config (collapsible) |
|
||||
| Tier 1: [gemini v] [gemini-2.5-flash v] [None v] |
|
||||
| Tier 1: [gemini v] [gemini-2.5-flash v] [None v] |
|
||||
+---------------------------------------------------------+
|
||||
"""
|
||||
imgui.text("Tier Usage (Tokens & Cost)")
|
||||
@@ -6680,7 +6671,7 @@ def render_mma_ticket_editor(app: App) -> None:
|
||||
| Editing: ticket-042 |
|
||||
| Status: in_progress |
|
||||
| Priority: [medium v] |
|
||||
| Target: src/gui_2.py |
|
||||
| Target: src/gui_2.py |
|
||||
| Depends on: ticket-041, ticket-040 |
|
||||
| Persona Override: [None v] |
|
||||
| [Mark Complete] [Delete] |
|
||||
@@ -6738,13 +6729,11 @@ def render_mma_agent_streams(app: App) -> None:
|
||||
imgui.end_tab_bar()
|
||||
|
||||
def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) -> None:
|
||||
"""
|
||||
Renders a single tier's live streaming text panel. For Tier 1, 2, and 4 a single scrollable
|
||||
"""Renders a single tier's live streaming text panel. For Tier 1, 2, and 4 a single scrollable
|
||||
selectable text area is shown; for Tier 3 (stream_key=None), each worker ticket gets
|
||||
its own labelled, colour-coded sub-child with an auto-scroll behaviour.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:stream_text] => [I:single_scroll] | [I:worker_sub_children]`
|
||||
SSDL: `[I:stream_text] => [I:single_scroll] | [I:worker_sub_children]`
|
||||
|
||||
ASCII Layout Map (single-stream, e.g. Tier 1):
|
||||
+---------------------------------------------------------+
|
||||
@@ -6813,13 +6802,11 @@ def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) ->
|
||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_tier_stream_panel")
|
||||
|
||||
def render_track_proposal_modal(app: App) -> None:
|
||||
"""
|
||||
Renders the Track Proposal modal. Shows Tier 1's generated implementation tracks
|
||||
"""Renders the Track Proposal modal. Shows Tier 1's generated implementation tracks
|
||||
with editable title and goal fields, and buttons to remove, start individual tracks,
|
||||
accept all, or cancel.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:proposed_tracks] -> [B:edit_title/goal] -> [B:remove/start] => [B:accept_all | B:cancel]`
|
||||
SSDL: `[I:proposed_tracks] -> [B:edit_title/goal] -> [B:remove/start] => [B:accept_all | B:cancel]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -6880,13 +6867,11 @@ def render_track_proposal_modal(app: App) -> None:
|
||||
imgui.end_popup()
|
||||
|
||||
def render_ticket_queue(app: App) -> None:
|
||||
"""
|
||||
Renders the Ticket Queue Management panel. Provides select-all/none controls,
|
||||
"""Renders the Ticket Queue Management panel. Provides select-all/none controls,
|
||||
bulk action buttons, a 7-column scrollable table of tickets with drag-to-reorder,
|
||||
priority/model combos, status labels, and per-row Kill/Block/Unblock actions.
|
||||
|
||||
SSDL Shape:
|
||||
`[B:select_all/none] -> [B:bulk_actions] -> [I:ticket_table] => [I:ticket_editor?]`
|
||||
SSDL: `[B:select_all/none] -> [B:bulk_actions] -> [I:ticket_table] => [I:ticket_editor?]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -7013,12 +6998,10 @@ def render_ticket_queue(app: App) -> None:
|
||||
imgui.end_table()
|
||||
|
||||
def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
||||
"""
|
||||
Renders the interactive node editor DAG visualizer, mapping ticket relationships
|
||||
"""Renders the interactive node editor DAG visualizer, mapping ticket relationships
|
||||
and allowing creation or deletion of links.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:task_nodes] -> [B:node_editor_canvas] => [I:link_connections]`
|
||||
SSDL: `[I:task_nodes] -> [B:node_editor_canvas] => [I:link_connections]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -7089,8 +7072,8 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
||||
tid = str(t.get('id', ''))
|
||||
if abs(hash(tid + "_out")) == s_id: source_tid = tid
|
||||
if abs(hash(tid + "_out")) == e_id: source_tid = tid
|
||||
if abs(hash(tid + "_in")) == s_id: target_tid = tid
|
||||
if abs(hash(tid + "_in")) == e_id: target_tid = tid
|
||||
if abs(hash(tid + "_in")) == s_id: target_tid = tid
|
||||
if abs(hash(tid + "_in")) == e_id: target_tid = tid
|
||||
if source_tid and target_tid and source_tid != target_tid:
|
||||
for t in app.active_tickets:
|
||||
if str(t.get('id', '')) == target_tid:
|
||||
@@ -7136,17 +7119,17 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
||||
if tid.startswith('T-'):
|
||||
try: max_id = max(max_id, int(tid[2:]))
|
||||
except: pass
|
||||
app.ui_new_ticket_id = f"T-{max_id + 1:03d}"
|
||||
app.ui_new_ticket_desc = ""
|
||||
app.ui_new_ticket_id = f"T-{max_id + 1:03d}"
|
||||
app.ui_new_ticket_desc = ""
|
||||
app.ui_new_ticket_target = ""
|
||||
app.ui_new_ticket_deps = ""
|
||||
app.ui_new_ticket_deps = ""
|
||||
if app._show_add_ticket_form:
|
||||
imgui.begin_child("add_ticket_form", imgui.ImVec2(-1, 220), True)
|
||||
imgui.text_colored(C_VAL(), "New Ticket Details")
|
||||
_, app.ui_new_ticket_id = imgui.input_text("ID##new_ticket", app.ui_new_ticket_id)
|
||||
_, app.ui_new_ticket_desc = imgui.input_text_multiline("Description##new_ticket", app.ui_new_ticket_desc, imgui.ImVec2(-1, 60))
|
||||
_, app.ui_new_ticket_id = imgui.input_text("ID##new_ticket", app.ui_new_ticket_id)
|
||||
_, app.ui_new_ticket_desc = imgui.input_text_multiline("Description##new_ticket", app.ui_new_ticket_desc, imgui.ImVec2(-1, 60))
|
||||
_, app.ui_new_ticket_target = imgui.input_text("Target File##new_ticket", app.ui_new_ticket_target)
|
||||
_, app.ui_new_ticket_deps = imgui.input_text("Depends On (IDs, comma-separated)##new_ticket", app.ui_new_ticket_deps)
|
||||
_, app.ui_new_ticket_deps = imgui.input_text("Depends On (IDs, comma-separated)##new_ticket", app.ui_new_ticket_deps)
|
||||
imgui.text("Priority:")
|
||||
imgui.same_line()
|
||||
if imgui.begin_combo("##new_prio", app.ui_new_ticket_priority):
|
||||
|
||||
Reference in New Issue
Block a user