From 8df8e885e7aaf113c326b4ed6f20ad6d2b04f872 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 18 May 2026 17:01:00 -0400 Subject: [PATCH 1/8] Improve browse_feedback_sessions UI - Move 'View Panelists' from help area to a proper tab in tabbed_templates_html - Add subject field to view_panelists template for tab label - Wrap each interview's feedback in a Bootstrap 5 collapse (expanded by default) so reviewers can collapse per-interview sections - Sort open answer feedback in reverse chronological order (newest first) - Convert markdown inside collapse divs to HTML (blockquote, hr, links) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../questions/browse_feedback_sessions.yml | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index ce45e5c..e0b0feb 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -24,12 +24,7 @@ question: | subquestion: | ${ action_button_html(url_action('toggle_archived'), label="Show archived" if not show_archived else "Hide archived", color="secondary")} - ${ tabbed_templates_html("Feedback tabs", reviews_table_template, feedback_select_template)} -help: - label: | - View Panelists - content: | - ${ view_panelists } + ${ tabbed_templates_html("Feedback tabs", reviews_table_template, feedback_select_template, view_panelists)} --- template: reviews_table_template subject: Review Scores @@ -45,17 +40,15 @@ content: | template: feedback_select_template subject: Open answer feedback content: | - % for interview, review_list in text_reviews.items(): -

In ${ interview }

+ % for idx, (interview, review_list) in enumerate(text_reviews.items()): +

In ${ interview }

+
% for review in review_list: % if review['archived']: - **ARCHIVED** +

ARCHIVED

% endif - - On ${ review['datetime'] }: - - > ${ review['body'] } - +

On ${ review['datetime'] }:

+
${ review['body'] }
% if not review.get('html_url'): % if review.get('github_user'): ${ action_button_html(prefill_github_issue_url(repo_owner=review.get('github_user'), repo_name=review.get('github_repo_name'), title="User feedback", body=review['body'], label=al_github_label), label="Make a github issue") } @@ -63,8 +56,7 @@ content: | ${ action_button_html(prefill_github_issue_url(repo_name=interview.split(":")[0].replace(".", "-"), title="User feedback", body=review['body'], label=al_github_label), label="Make a github issue") } % endif % else: - [Link to Github issue](${ review.get('html_url') }) - + Link to Github issue % endif % if review.get('session_id'): ${ action_button_html(url_action('open_session', interview=review['interview'], session_id=review.get('session_id')), label='Open Session', color='secondary') } @@ -72,11 +64,9 @@ content: | % if not review['archived']: ${ action_button_html(url_action('mark_as_archived', feedback_id=review['id']), label="Archive", color="danger")} % endif - - --- - +
% endfor - +
% endfor --- template: what_are_reviews_template @@ -92,6 +82,7 @@ content: | affect people's reviews. --- template: view_panelists +subject: View Panelists content: | % for email_and_time in potential_panelists(): % if isinstance(email_and_time[0], bytes): @@ -114,6 +105,8 @@ code: | text_reviews[info['interview']].append(info) else: text_reviews[info['interview']] = [info] + for interview in text_reviews: + text_reviews[interview].sort(key=lambda r: r['datetime'], reverse=True) --- event: open_session code: | From d89279173d48bd22ec01675189e8d6295197d7fa Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 18 May 2026 17:08:36 -0400 Subject: [PATCH 2/8] Fix table rendering; move sorting to SQL layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert markdown table to HTML in reviews_table_template — markdown tables don't render after a block-level HTML element (collapse_template) - Add ORDER BY datetime DESC to get_all_feedback_info query so reviews are sorted newest-first at the database level - Since SQL now returns rows newest-first, inserting into the dict naturally orders interviews by their most recent review (first encounter per interview = most recent entry for that interview) - Remove Python-side sort from text_reviews code block Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../data/questions/browse_feedback_sessions.yml | 11 ++++++----- docassemble/GithubFeedbackForm/feedback_on_server.py | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index e0b0feb..4bd0702 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -31,11 +31,14 @@ subject: Review Scores content: | ${ collapse_template(what_are_reviews_template) } - Interview file | Version | Number of reviews | Average Score - -------------- |---------|-------------------|--------------- + + + % for review_agg in get_good_or_bad(): - ${ review_agg['interview'] } | ${ review_agg['version'] } | ${ review_agg['count'] } | ${ str(round(review_agg['average'] * 1000)/1000) } + % endfor + +
Interview fileVersionNumber of reviewsAverage Score
${ review_agg['interview'] }${ review_agg['version'] }${ review_agg['count'] }${ str(round(review_agg['average'] * 1000)/1000) }
--- template: feedback_select_template subject: Open answer feedback @@ -105,8 +108,6 @@ code: | text_reviews[info['interview']].append(info) else: text_reviews[info['interview']] = [info] - for interview in text_reviews: - text_reviews[interview].sort(key=lambda r: r['datetime'], reverse=True) --- event: open_session code: | diff --git a/docassemble/GithubFeedbackForm/feedback_on_server.py b/docassemble/GithubFeedbackForm/feedback_on_server.py index fd554f1..76545fb 100644 --- a/docassemble/GithubFeedbackForm/feedback_on_server.py +++ b/docassemble/GithubFeedbackForm/feedback_on_server.py @@ -211,6 +211,7 @@ def get_all_feedback_info(interview=None, include_archived=False) -> Iterable: stmt = stmt.where(feedback_session_table.c.interview == interview) if not include_archived: stmt = stmt.where(feedback_session_table.c.archived == False) + stmt = stmt.order_by(desc(feedback_session_table.c.datetime)) with engine.begin() as conn: results = conn.execute(stmt) # Turn into literal dict because DA is too eager to save / load SQLAlchemy objects into the interview SQL From 2601e16be3ed0baca440bd3b2b78c0890e00a22c Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 18 May 2026 17:10:59 -0400 Subject: [PATCH 3/8] Add collapse/expand icon affordance to interview sections Uses ALToolbox's existing pdcaretopen/pdcaretclosed CSS pattern with fa_icon caret-down (expanded) and caret-right (collapsed). Bootstrap toggles the 'collapsed' class on the anchor automatically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../data/questions/browse_feedback_sessions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index 4bd0702..bfd1c2c 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -44,7 +44,7 @@ template: feedback_select_template subject: Open answer feedback content: | % for idx, (interview, review_list) in enumerate(text_reviews.items()): -

In ${ interview }

+ ${ fa_icon("caret-down") }${ fa_icon("caret-right") }

In ${ interview }

% for review in review_list: % if review['archived']: From 93491e0c3254d4e5319b10134c7dc65cb278add4 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 18 May 2026 17:14:13 -0400 Subject: [PATCH 4/8] Render feedback body as HTML to fix markdown tables in accordions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ${ review['body'] } with ${ markdown_to_html(review['body']) }. markdown_to_html() converts the body text (which may contain pipe tables, code spans, etc.) to HTML during Mako evaluation — before the outer Markdown pass runs. The resulting HTML is then embedded inside the
as raw HTML and passes through unchanged, bypassing the md_in_html nesting limitation that prevents Markdown processing inside block-level HTML elements without explicit markdown="1" attributes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../data/questions/browse_feedback_sessions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index bfd1c2c..7a155a7 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -51,7 +51,7 @@ content: |

ARCHIVED

% endif

On ${ review['datetime'] }:

-
${ review['body'] }
+
${ markdown_to_html(review['body']) }
% if not review.get('html_url'): % if review.get('github_user'): ${ action_button_html(prefill_github_issue_url(repo_owner=review.get('github_user'), repo_name=review.get('github_repo_name'), title="User feedback", body=review['body'], label=al_github_label), label="Make a github issue") } From 03421ec1e269c47162e6fa3a9d9f0c7ffb1f1628 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Tue, 19 May 2026 06:30:07 -0400 Subject: [PATCH 5/8] Export markdown_to_html via feedback_on_server module Import from docassemble.base.filter and add to __all__ so the interview namespace can resolve it when rendering feedback body content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docassemble/GithubFeedbackForm/feedback_on_server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docassemble/GithubFeedbackForm/feedback_on_server.py b/docassemble/GithubFeedbackForm/feedback_on_server.py index 76545fb..bd6fa3f 100644 --- a/docassemble/GithubFeedbackForm/feedback_on_server.py +++ b/docassemble/GithubFeedbackForm/feedback_on_server.py @@ -25,6 +25,7 @@ from alembic.config import Config from alembic import command from docassemble.base.util import DARedis, log +from docassemble.base.filter import markdown_to_html from docassemble.base.sql import alchemy_url, connect_args __all__ = [ @@ -37,6 +38,7 @@ "get_all_feedback_info", "save_good_or_bad", "get_good_or_bad", + "markdown_to_html", ] redis_panel_emails_key = "docassemble-GithubFeedbackForm:panel_emails" From 11033e11f1bcd232af9c4fab7bca75759d72be3b Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Tue, 19 May 2026 07:06:03 -0400 Subject: [PATCH 6/8] Fix collapse toggle: wrap in al_collapse_template, use span for title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap each interview section in
so ALToolbox's collapse_template.css selectors (.al_collapse_template a span.pdcaretopen/pdcaretclosed) apply — this fixes both icons showing simultaneously and styles the toggle link as a dashed-underline control (not a plain blue hyperlink) - Replace

with so the title stays inline with the caret icon (h3 is block-level) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../data/questions/browse_feedback_sessions.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index 7a155a7..737d67e 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -44,7 +44,8 @@ template: feedback_select_template subject: Open answer feedback content: | % for idx, (interview, review_list) in enumerate(text_reviews.items()): - ${ fa_icon("caret-down") }${ fa_icon("caret-right") }

In ${ interview }

+
+ ${ fa_icon("caret-down") }${ fa_icon("caret-right") } In ${ interview }
% for review in review_list: % if review['archived']: @@ -70,6 +71,7 @@ content: |
% endfor
+
% endfor --- template: what_are_reviews_template From 4a943dce478298645fc6f008b605f22c1667dfd3 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Tue, 19 May 2026 07:14:25 -0400 Subject: [PATCH 7/8] Add pytest to dev dependencies uv run pytest fails because pytest is not declared in [dependency-groups] dev, so uv has no package to spawn. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 5c91454..d84858a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ dev = [ "docassemble.base>=1.4", "docassemble.webapp", "mypy", + "pytest", "types-requests", "testcontainers", ] From 8b70b6a23fd7ca10e14d50248b33894d7ba17ae6 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Tue, 19 May 2026 07:15:40 -0400 Subject: [PATCH 8/8] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../data/questions/browse_feedback_sessions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml index 737d67e..55cd159 100644 --- a/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml +++ b/docassemble/GithubFeedbackForm/data/questions/browse_feedback_sessions.yml @@ -60,7 +60,7 @@ content: | ${ action_button_html(prefill_github_issue_url(repo_name=interview.split(":")[0].replace(".", "-"), title="User feedback", body=review['body'], label=al_github_label), label="Make a github issue") } % endif % else: - Link to Github issue + Link to GitHub issue % endif % if review.get('session_id'): ${ action_button_html(url_action('open_session', interview=review['interview'], session_id=review.get('session_id')), label='Open Session', color='secondary') }