add clickable admin list rows and supplier owner impersonation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Clickable admin list rows** — entire row is clickable on leads, suppliers,
|
||||||
|
and users admin list pages (`data-href` + JS click handler that skips
|
||||||
|
links/buttons/forms); pointer cursor and hover highlight via CSS
|
||||||
|
- **Supplier impersonation** — "Impersonate Owner" button on admin supplier
|
||||||
|
detail page; reuses existing `admin.impersonate` route, shown only when
|
||||||
|
the supplier has a `claimed_by` user
|
||||||
|
|
||||||
### Added — Programmatic SEO: Content Generation Engine
|
### Added — Programmatic SEO: Content Generation Engine
|
||||||
- **Database migration 0010** — `published_scenarios`, `article_templates`,
|
- **Database migration 0010** — `published_scenarios`, `article_templates`,
|
||||||
`template_data`, `articles` tables with FTS5 full-text search on articles;
|
`template_data`, `articles` tables with FTS5 full-text search on articles;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for lead in leads %}
|
{% for lead in leads %}
|
||||||
<tr>
|
<tr data-href="{{ url_for('admin.lead_detail', lead_id=lead.id) }}">
|
||||||
<td><a href="{{ url_for('admin.lead_detail', lead_id=lead.id) }}">#{{ lead.id }}</a></td>
|
<td><a href="{{ url_for('admin.lead_detail', lead_id=lead.id) }}">#{{ lead.id }}</a></td>
|
||||||
<td>
|
<td>
|
||||||
{% if lead.heat_score == 'hot' %}
|
{% if lead.heat_score == 'hot' %}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for s in suppliers %}
|
{% for s in suppliers %}
|
||||||
<tr>
|
<tr data-href="{{ url_for('admin.supplier_detail', supplier_id=s.id) }}">
|
||||||
<td><a href="{{ url_for('admin.supplier_detail', supplier_id=s.id) }}">#{{ s.id }}</a></td>
|
<td><a href="{{ url_for('admin.supplier_detail', supplier_id=s.id) }}">#{{ s.id }}</a></td>
|
||||||
<td>
|
<td>
|
||||||
<span class="text-sm font-semibold">{{ s.name }}</span>
|
<span class="text-sm font-semibold">{{ s.name }}</span>
|
||||||
|
|||||||
@@ -13,7 +13,15 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<p class="text-sm text-slate mt-1">{{ supplier.slug }} · {{ supplier.country_code or '-' }}</p>
|
<p class="text-sm text-slate mt-1">{{ supplier.slug }} · {{ supplier.country_code or '-' }}</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="{{ url_for('directory.supplier_detail', slug=supplier.slug) }}" class="btn-outline" target="_blank">View Profile</a>
|
<div class="flex gap-2">
|
||||||
|
{% if supplier.claimed_by %}
|
||||||
|
<form method="post" action="{{ url_for('admin.impersonate', user_id=supplier.claimed_by) }}" class="m-0">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button type="submit" class="btn-outline">Impersonate Owner</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ url_for('directory.supplier_detail', slug=supplier.slug) }}" class="btn-outline" target="_blank">View Profile</a>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="grid-2" style="gap:1.5rem">
|
<div class="grid-2" style="gap:1.5rem">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for u in users %}
|
{% for u in users %}
|
||||||
<tr>
|
<tr data-href="{{ url_for('admin.user_detail', user_id=u.id) }}">
|
||||||
<td class="mono text-sm">{{ u.id }}</td>
|
<td class="mono text-sm">{{ u.id }}</td>
|
||||||
<td><a href="{{ url_for('admin.user_detail', user_id=u.id) }}">{{ u.email }}</a></td>
|
<td><a href="{{ url_for('admin.user_detail', user_id=u.id) }}">{{ u.email }}</a></td>
|
||||||
<td>{{ u.name or '-' }}</td>
|
<td>{{ u.name or '-' }}</td>
|
||||||
|
|||||||
@@ -150,6 +150,16 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Clickable table rows (admin lists) -->
|
||||||
|
<style>tr[data-href]{cursor:pointer}tr[data-href]:hover{background:#F8FAFC}</style>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("click",function(e){
|
||||||
|
var row=e.target.closest("tr[data-href]");
|
||||||
|
if(!row||e.target.closest("a,button,form,input,select,textarea"))return;
|
||||||
|
window.location=row.dataset.href;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{% block scripts %}{% endblock %}
|
{% block scripts %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user