fix(admissions): switch to EES content API + correct publication slug and columns
All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 50s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m12s
Build and Push Docker Images / Build Integrator (push) Successful in 57s
Build and Push Docker Images / Build Kestra Init (push) Successful in 33s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s

The EES statistics API only exposes ~13 publications; admissions data is not
among them. Switch to the EES content API (content.explore-education-statistics.
service.gov.uk) which covers all publications.

- ees.py: add get_content_release_id() and download_release_zip_csv() that
  fetch the release ZIP and extract a named CSV member from it
- admissions.py: use corrected slug (primary-and-secondary-school-applications-
  and-offers), correct column names from actual CSV (school_urn,
  total_number_places_offered, times_put_as_1st_preference, etc.), derive
  first_preference_offers_pct from offer/application ratio, filter to primary
  schools only, keep most recent year per URN

Also includes SchoolDetailView UX redesign: parent-first section ordering,
plain-English labels, national average benchmarks, progress score colour
coding, expanded header, quick summary strip, and CSS consolidation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-25 10:06:36 +00:00
parent 00dca39fbd
commit b68063c9b9
5 changed files with 951 additions and 652 deletions

View File

@@ -50,7 +50,34 @@
.address {
font-size: 0.875rem;
color: var(--text-muted, #8a847a);
margin: 0;
margin: 0 0 0.75rem;
}
/* Expanded header details (headteacher, website, trust, pupils) */
.headerDetails {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.25rem;
margin-top: 0.5rem;
}
.headerDetail {
font-size: 0.8125rem;
color: var(--text-secondary, #5c564d);
}
.headerDetail strong {
color: var(--text-primary, #1a1612);
font-weight: 600;
}
.headerDetail a {
color: var(--accent-teal, #2d7d7d);
text-decoration: none;
}
.headerDetail a:hover {
text-decoration: underline;
}
.actions {
@@ -90,6 +117,50 @@
opacity: 0.9;
}
/* Quick Summary Strip */
.summaryStrip {
display: flex;
gap: 0.625rem;
flex-wrap: wrap;
margin: 0 0 1.25rem;
}
.summaryPill {
padding: 0.35rem 0.875rem;
border-radius: 999px;
font-size: 0.8125rem;
font-weight: 600;
display: inline-flex;
align-items: center;
gap: 0.3rem;
}
.summaryPillGood {
background: #d1fae5;
color: #065f46;
}
.summaryPillWarn {
background: #fef3c7;
color: #92400e;
}
.summaryPillBad {
background: #fee2e2;
color: #991b1b;
}
/* Unified card — replaces summary / chartsSection / detailedMetrics /
absenceSection / historySection / supplementarySection / mapSection */
.card {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1.25rem 1.5rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
}
/* Section Title */
.sectionTitle {
font-size: 1.125rem;
@@ -102,6 +173,7 @@
display: flex;
align-items: center;
gap: 0.375rem;
flex-wrap: wrap;
}
.sectionTitle::before {
@@ -111,18 +183,35 @@
height: 1em;
background: var(--accent-coral, #e07256);
border-radius: 2px;
flex-shrink: 0;
}
/* Summary Section */
.summary {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
.sectionSubtitle {
font-size: 0.85rem;
color: var(--text-muted, #8a847a);
margin: -0.5rem 0 1rem;
}
/* Response count badge (used in "What Parents Say") */
.responseBadge {
font-size: 0.75rem;
font-weight: 500;
font-family: var(--font-dm-sans), sans-serif;
color: var(--text-muted, #8a847a);
background: var(--bg-secondary, #f3ede4);
padding: 0.1rem 0.5rem;
border-radius: 999px;
margin-left: auto;
}
.subSectionTitle {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-secondary, #5c564d);
margin: 1.25rem 0 0.75rem;
}
/* Metrics Grid & Cards */
.metricsGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
@@ -156,21 +245,30 @@
gap: 0.25rem;
}
.metricHint {
font-size: 0.7rem;
color: var(--text-muted, #8a847a);
margin-top: 0.3rem;
font-style: italic;
}
.metricTrend {
font-size: 1rem;
color: var(--accent-teal, #2d7d7d);
}
/* Charts Section */
.chartsSection {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
/* Progress score colour coding */
.progressPositive {
color: var(--accent-teal, #2d7d7d);
font-weight: 700;
}
.progressNegative {
color: var(--accent-coral, #e07256);
font-weight: 700;
}
/* Charts Section */
.chartContainer {
width: 100%;
height: 280px;
@@ -178,15 +276,6 @@
}
/* Detailed Metrics - Compact Grid Layout */
.detailedMetrics {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
}
.metricGroupsGrid {
display: grid;
grid-template-columns: repeat(3, 1fr);
@@ -235,53 +324,7 @@
color: var(--accent-teal, #2d7d7d);
}
/* Absence Section */
.absenceSection {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
}
.absenceGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.75rem;
}
.absenceCard {
background: var(--bg-secondary, #f3ede4);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 6px;
padding: 0.75rem 1rem;
text-align: center;
}
.absenceLabel {
font-size: 0.75rem;
color: var(--text-muted, #8a847a);
margin-bottom: 0.25rem;
font-weight: 500;
}
.absenceValue {
font-size: 1.125rem;
font-weight: 700;
color: var(--text-primary, #1a1612);
}
/* Map Section */
.mapSection {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
}
/* Map */
.mapContainer {
width: 100%;
height: 250px;
@@ -290,16 +333,7 @@
border: 1px solid var(--border-color, #e5dfd5);
}
/* History Section */
.historySection {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
box-shadow: var(--shadow-soft);
}
/* History Table */
.tableWrapper {
overflow-x: auto;
margin-top: 0.5rem;
@@ -345,7 +379,186 @@
color: var(--accent-gold, #c9a227);
}
/* Responsive Design */
/* Ofsted */
.ofstedHeader {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 1rem;
}
.ofstedGrade {
display: inline-block;
padding: 0.3rem 0.75rem;
font-size: 1rem;
font-weight: 700;
border-radius: 6px;
white-space: nowrap;
}
.ofstedGrade1 { background: rgba(45, 125, 125, 0.12); color: var(--accent-teal, #2d7d7d); }
.ofstedGrade2 { background: rgba(60, 140, 60, 0.12); color: #3c8c3c; }
.ofstedGrade3 { background: rgba(201, 162, 39, 0.15); color: #b8920e; }
.ofstedGrade4 { background: rgba(224, 114, 86, 0.15); color: var(--accent-coral, #e07256); }
.ofstedDate {
font-size: 0.85rem;
color: var(--text-muted, #8a847a);
}
.ofstedPrevious {
font-size: 0.8125rem;
color: var(--text-muted, #8a847a);
font-style: italic;
}
.ofstedReportLink {
font-size: 0.8125rem;
color: var(--accent-teal, #2d7d7d);
text-decoration: none;
margin-left: auto;
white-space: nowrap;
}
.ofstedReportLink:hover {
text-decoration: underline;
}
/* Parent View */
.parentViewGrid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.parentViewRow {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.875rem;
}
.parentViewLabel {
flex: 0 0 18rem;
color: var(--text-secondary, #5c564d);
font-size: 0.8125rem;
}
.parentViewBar {
flex: 1;
height: 0.5rem;
background: var(--bg-secondary, #f3ede4);
border-radius: 4px;
overflow: hidden;
}
.parentViewFill {
height: 100%;
background: var(--accent-teal, #2d7d7d);
border-radius: 4px;
transition: width 0.4s ease;
}
.parentViewPct {
flex: 0 0 2.75rem;
text-align: right;
font-size: 0.8125rem;
font-weight: 600;
color: var(--text-primary, #1a1612);
}
/* Admissions badges */
.admissionsBadge {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.3rem 0.75rem;
border-radius: 6px;
font-size: 0.8125rem;
font-weight: 600;
margin-top: 0.75rem;
}
.admissionsBadgeWarn {
background: rgba(201, 162, 39, 0.15);
color: #b8920e;
}
.admissionsBadgeGood {
background: rgba(60, 140, 60, 0.12);
color: #3c8c3c;
}
/* Deprivation dot scale */
.deprivationDots {
display: flex;
gap: 0.375rem;
margin: 0.75rem 0 0.5rem;
align-items: center;
}
.deprivationDot {
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
background: var(--bg-secondary, #f3ede4);
border: 2px solid var(--border-color, #e5dfd5);
flex-shrink: 0;
}
.deprivationDotFilled {
background: var(--accent-teal, #2d7d7d);
border-color: var(--accent-teal, #2d7d7d);
}
.deprivationDesc {
font-size: 0.875rem;
color: var(--text-secondary, #5c564d);
line-height: 1.5;
margin: 0;
}
.deprivationScaleLabel {
display: flex;
justify-content: space-between;
font-size: 0.7rem;
color: var(--text-muted, #8a847a);
margin-top: 0.25rem;
}
/* Progress note */
.progressNote {
margin-top: 0.75rem;
font-size: 0.8rem;
color: var(--text-muted);
font-style: italic;
}
/* Back navigation */
.backNav {
padding: 1rem var(--page-padding, 2rem);
padding-bottom: 0;
}
.backButton {
background: none;
border: none;
color: var(--text-secondary);
font-size: 0.875rem;
cursor: pointer;
padding: 0.375rem 0;
display: inline-flex;
align-items: center;
gap: 0.25rem;
transition: color var(--transition);
}
.backButton:hover {
color: var(--text-primary);
}
/* ── Responsive ──────────────────────────────────────── */
@media (max-width: 768px) {
.headerContent {
flex-direction: column;
@@ -396,148 +609,27 @@
}
}
.backNav {
padding: 1rem var(--page-padding, 2rem);
padding-bottom: 0;
}
.backButton {
background: none;
border: none;
color: var(--text-secondary);
font-size: 0.875rem;
cursor: pointer;
padding: 0.375rem 0;
display: inline-flex;
align-items: center;
gap: 0.25rem;
transition: color var(--transition);
}
.backButton:hover {
color: var(--text-primary);
}
.progressNote {
margin-top: 0.75rem;
font-size: 0.8rem;
color: var(--text-muted);
font-style: italic;
}
/* ── Supplementary Data Sections ──────────────────────── */
.supplementarySection {
background: var(--bg-card, white);
border: 1px solid var(--border-color, #e5dfd5);
border-radius: 10px;
padding: 1.25rem 1.5rem;
}
.supplementarySubtitle {
font-size: 0.85rem;
color: var(--text-muted, #8a847a);
margin-bottom: 1rem;
}
.subSectionTitle {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-secondary, #5c564d);
margin: 1.25rem 0 0.75rem;
}
/* Ofsted */
.ofstedHeader {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
}
.ofstedGrade {
display: inline-block;
padding: 0.3rem 0.75rem;
font-size: 1rem;
font-weight: 700;
border-radius: 6px;
white-space: nowrap;
}
.ofstedGrade1 { background: rgba(45, 125, 125, 0.12); color: var(--accent-teal, #2d7d7d); }
.ofstedGrade2 { background: rgba(60, 140, 60, 0.12); color: #3c8c3c; }
.ofstedGrade3 { background: rgba(201, 162, 39, 0.15); color: #b8920e; }
.ofstedGrade4 { background: rgba(224, 114, 86, 0.15); color: var(--accent-coral, #e07256); }
.ofstedDate {
font-size: 0.85rem;
color: var(--text-muted, #8a847a);
}
.ofstedType {
font-size: 0.8rem;
color: var(--text-muted, #8a847a);
margin-top: 0.5rem;
font-style: italic;
}
/* Parent View */
.parentViewGrid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.parentViewRow {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.875rem;
}
.parentViewLabel {
flex: 0 0 18rem;
color: var(--text-secondary, #5c564d);
font-size: 0.8125rem;
}
.parentViewBar {
flex: 1;
height: 0.5rem;
background: var(--bg-secondary, #f3ede4);
border-radius: 4px;
overflow: hidden;
}
.parentViewFill {
height: 100%;
background: var(--accent-teal, #2d7d7d);
border-radius: 4px;
transition: width 0.4s ease;
}
.parentViewPct {
flex: 0 0 2.75rem;
text-align: right;
font-size: 0.8125rem;
font-weight: 600;
color: var(--text-primary, #1a1612);
}
/* Metric hint (small label below metricValue) */
.metricHint {
font-size: 0.75rem;
color: var(--text-muted, #8a847a);
margin-top: 0.25rem;
font-style: italic;
}
/* ── Mobile ──────────────────────────────────────────── */
@media (max-width: 640px) {
.supplementarySection {
padding: 1rem;
@media (max-width: 480px) {
.parentViewRow {
flex-direction: column;
align-items: flex-start;
gap: 0.25rem;
}
.parentViewLabel {
flex: 0 0 10rem;
flex: none;
max-width: 100%;
}
.parentViewBar {
width: 100%;
}
.parentViewPct {
flex: none;
}
.card {
padding: 1rem;
}
}