{# 02 / SCRAPING PLAN -- step-by-step actions, one card per FlowSegmentation.Action. Replaces the v0.1.0 endpoints_table.html. Each card lists the click target + the Bucket A calls triggered by that click, plus copy-pasteable curl + httpx snippets that thread ``recommended_headers`` from the validation pass. T13: when ``report.skipped_filter`` is True (the user picked "Continue with generic report" on the post-capture confirmation step), we replace the action-card layout with a flat v0.1.x-style endpoint table -- there's no Bucket A segmentation to render against, so listing every captured endpoint is the most useful surface. Inline styles (styles.css is byte-pinned to the mockup). All colour tokens come from the existing CSS variables so light + dark themes render identically. #}
02 / SCRAPING PLAN
{% if report.skipped_filter %} {# T13: generic fallback. Render every captured endpoint in a flat table -- no Bucket A / B segmentation, no per-action grouping. The header copy makes the trade-off explicit so users understand why this layout differs from the standard rich one. #}

Captured endpoints

{% set endpoints = report.analysis_result.endpoints %} {% if endpoints %}

{{ endpoints | length }} endpoint{{ '' if (endpoints | length) == 1 else 's' }} captured. Generic-report mode skipped intent filtering, so every API call recorded during the capture appears below.

{% for ep in endpoints %} {% endfor %}
Method URL template Response
{{ ep.method or 'GET' }} {{ ep.url_template }} {{ ep.response_summary or '' }}
{% else %}

No endpoints were captured during this scan.

{% endif %} {% else %}

Step-by-step actions

{% set actions = report.analysis_result.flow_segmentation.actions %} {% set bg_requests = report.analysis_result.flow_segmentation.background_requests %} {% if actions %}

{{ actions | length }} user action{{ '' if (actions | length) == 1 else 's' }} captured. Each card shows the click and the data calls it triggered, with ready-to-paste curl + Python snippets.

{% else %}

No click-driven actions were segmented from this capture. The site may render data on initial load only -- inspect the prerequisites + evidence sections below.

{% endif %} {% for action in actions %} {% set bucket_a_calls = bucket_a_calls_in_action(report, action.requests) %}
Step {{ loop.index }}: {{ action.label or 'User action' }}
{% if action.started_at %} t+{{ '%.2f' | format(action.started_at) }}s {% endif %}
{% if action.click_target %}
{%- if action.click_target.get('tag') -%} <{{ action.click_target.get('tag') }}> {%- endif %} {% if action.click_target.get('text') %} "{{ action.click_target.get('text') }}" {% endif %} {% if action.click_target.get('href') %} → href={{ action.click_target.get('href') }} {% endif %}
{% endif %} {% if bucket_a_calls %}
Data calls triggered ({{ bucket_a_calls | length }})
{% for call in bucket_a_calls %} {% set tab_id = 'snippet-' ~ loop.index0 ~ '-' ~ loop.index %} {% set parent_idx = loop.index0 %}
{{ call.method }} {{ call.url }} {# T34.9: replay outcome badge per Bucket A call. Renderer pre-computed ``call.replay_status`` against ``report.replay_per_endpoint``. #} {% if call.replay_status == 'matched' %} ✔ replay matched {% elif call.replay_status == 'mismatch' %} ⚠ replay mismatch {% else %} · not in replay sample {% endif %}
{% if call.response_summary %}
Response shape: {{ call.response_summary }}
{% endif %}
Show curl + Python snippets {# T34.8: tabbed code block. Both panes are present in the DOM so existing tests that grep for ``curl`` / ``httpx`` keep passing; the inactive pane is ``hidden``. A tiny inline ``onclick`` swaps the active tab (no JS framework). #}
{{ call.url | curl_snippet(call.method, call.headers, call.cookies, call.header_values, report.target_domain) }}
{% endfor %} {% else %}
No Bucket A data calls were tied to this action. {% if action.requests %} ({{ action.requests | length }} request{{ '' if (action.requests | length) == 1 else 's' }} fired but classified as bootstrap or noise.) {% endif %}
{% endif %}
{% endfor %} {% if bg_requests %}
Background requests ({{ bg_requests | length }})

XHR / fetch calls not tied to any user click -- typically analytics, lazy-loaded chunks, or polling endpoints.

    {% for url in bg_requests[:25] %}
  • {{ url }}
  • {% endfor %}
{% if (bg_requests | length) > 25 %}

and {{ (bg_requests | length) - 25 }} more not shown.

{% endif %}
{% endif %} {% endif %}