Skip to content

Commit 19636fa

Browse files
JacobCoffeeclaude
andcommitted
feat: insert managed legal clauses in composer step 6
Composer contract editor now shows insert buttons for each managed legal clause below the Legal Clauses textarea. Clicking a clause button appends its text to the field. Also removes the legal clause line from the admin-only guide section. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 19551e5 commit 19636fa

File tree

4 files changed

+41
-2
lines changed

4 files changed

+41
-2
lines changed

apps/sponsors/manage/tests.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,19 @@ def test_step6_renders(self):
19201920
self.assertContains(response, "Contract Editor")
19211921
self.assertContains(response, "Acme Corp")
19221922

1923+
def test_step6_shows_available_clauses(self):
1924+
"""Step 6 shows insert buttons for managed legal clauses."""
1925+
clause = LegalClause.objects.create(
1926+
internal_name="Trademark",
1927+
clause="Sponsor may use the Python trademark.",
1928+
)
1929+
response = self.client.get(reverse("manage_composer") + "?step=6")
1930+
self.assertEqual(response.status_code, 200)
1931+
self.assertContains(response, "Insert clause")
1932+
self.assertContains(response, "Trademark")
1933+
self.assertContains(response, clause.clause)
1934+
clause.delete()
1935+
19231936
def test_step6_save_contract(self):
19241937
response = self.client.post(
19251938
reverse("manage_composer") + "?step=6",

apps/sponsors/manage/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,7 @@ def _render_step6(self, request, data):
23972397
"contract_sponsor_contact": contract.sponsor_contact,
23982398
"contract_benefits_list": contract.benefits_list.raw,
23992399
"contract_legal_clauses": contract.legal_clauses.raw,
2400+
"available_clauses": LegalClause.objects.all().order_by("order"),
24002401
"default_subject": "Sponsorship Proposal from the Python Software Foundation",
24012402
"default_body": default_body,
24022403
}

apps/sponsors/templates/sponsors/manage/composer.html

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1355,8 +1355,34 @@ <h3 style="font-size:16px;font-weight:700;color:#1a1a2e;margin:0 0 16px;">Edit C
13551355
<button type="button" onclick="mdFootnoteRef(this)" title="Footnote ref">[^]</button>
13561356
<button type="button" onclick="mdFootnoteDef(this)" title="Footnote def">[^]:</button>
13571357
</div>
1358-
<textarea name="legal_clauses" rows="8" style="width:100%;padding:10px 12px;border:1px solid #ccc;border-radius:0 0 4px 4px;font-size:13px;font-family:monospace;box-sizing:border-box;resize:vertical;line-height:1.5;">{{ contract_legal_clauses }}</textarea>
1358+
<textarea name="legal_clauses" id="legal-clauses-textarea" rows="8" style="width:100%;padding:10px 12px;border:1px solid #ccc;border-radius:0 0 4px 4px;font-size:13px;font-family:monospace;box-sizing:border-box;resize:vertical;line-height:1.5;">{{ contract_legal_clauses }}</textarea>
13591359
</div>
1360+
{% if available_clauses %}
1361+
<div style="margin-top:8px;">
1362+
<div style="font-size:11px;font-weight:600;color:#999;margin-bottom:4px;">Insert clause:</div>
1363+
<div style="display:flex;gap:4px;flex-wrap:wrap;">
1364+
{% for clause in available_clauses %}
1365+
<button type="button" class="date-quick-btn" onclick="insertClause(this)" data-clause="{{ clause.clause|escapejs }}" data-name="{{ clause.internal_name|escapejs }}" title="{{ clause.clause|truncatechars:200 }}">{{ clause.internal_name }}</button>
1366+
{% endfor %}
1367+
</div>
1368+
</div>
1369+
<script>
1370+
function insertClause(btn) {
1371+
var ta = document.getElementById('legal-clauses-textarea');
1372+
var text = btn.getAttribute('data-clause');
1373+
var name = btn.getAttribute('data-name');
1374+
if (!ta || !text) return;
1375+
var val = ta.value;
1376+
if (val && !val.endsWith('\n')) val += '\n';
1377+
if (val) val += '\n';
1378+
ta.value = val + text;
1379+
ta.focus();
1380+
ta.scrollTop = ta.scrollHeight;
1381+
btn.style.opacity = '0.5';
1382+
btn.title = 'Inserted: ' + name;
1383+
}
1384+
</script>
1385+
{% endif %}
13601386
</div>
13611387

13621388
<button type="submit" class="btn btn-primary" style="padding:8px 20px;">Save Changes</button>

apps/sponsors/templates/sponsors/manage/guide.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ <h3 style="font-size:16px;font-weight:700;color:#e74c3c;border-bottom:2px solid
337337
<ul style="font-size:13px;line-height:2;color:#444;padding-left:20px;">
338338
<li><strong>Benefit ordering</strong> &mdash; drag-to-reorder benefits within a program. The manage UI shows them in order but doesn't let you rearrange</li>
339339
<li><strong>Benefit conflicts</strong> &mdash; configuring which benefits are mutually exclusive (M2M relationship in the admin)</li>
340-
<li><s>Legal clause CRUD</s> &mdash; now available under More &rarr; <a href="{% url 'manage_legal_clauses' %}" style="color:#3776ab;">Legal Clauses</a></li>
341340
<li><strong>Sponsorship program management</strong> &mdash; adding or editing programs (Foundation, PyCon, PyPI, etc.)</li>
342341
<li><strong>Advanced import/export</strong> &mdash; django-import-export for bulk data operations</li>
343342
<li><strong>Detailed asset filtering</strong> &mdash; filtering and administering individual uploaded assets across all sponsors</li>

0 commit comments

Comments
 (0)