{title}
+ {subtitle &&{subtitle}
} + {content ?? INFO_PAGES[page].map((block, i) =>From a9543bb4001ef88cd0ae605c7d522dd2004ed59a Mon Sep 17 00:00:00 2001
From: nando-bingani
{NOTES[state]}
+ {submission.submission_comments && ( ++ {submission.submission_comments} + {submission.reviewed_by && } ++ )} +
+ {published + ? 'This project is published. Marking it not accepted removes it from the public site.' + : 'Accepting publishes this project on the public site.'} +
+ +{emptyText}
; const max = Math.max(...rows.map((r) => r.count)); @@ -14,8 +14,10 @@ const BarList = ({ rows = [], total, emptyText = 'No data for this selection.' }| {labelHeader} | {data.series.map((s) =>{s} | )}Total |
|---|---|---|
| {r.label} | + {data.series.map((s) =>{(r.values[s] || 0).toLocaleString()} | )} +{data.series.reduce((n, s) => n + (r.values[s] || 0), 0).toLocaleString()} | +
{total(unspecified, series).toLocaleString()} projects {unspecifiedText}.
+ ); + if (!rows.length) return <>{{emptyText}
}{note}>; + const max = Math.max(...rows.map((r) => total(r, series))); + + return ( +{emptyText}
; + + const first = data.rows[0].label; + const last = data.rows[data.rows.length - 1].label; + const byYear = Object.fromEntries(data.rows.map((r) => [r.label, r.values])); + const years = Array.from({ length: last - first + 1 }, (_, i) => { + const values = byYear[first + i] || {}; + return { year: first + i, values, total: series.reduce((n, s) => n + (values[s] || 0), 0) }; + }); + + const width = Math.max(years.length * 28 + PAD.left + PAD.right, 320); + const plotW = width - PAD.left - PAD.right; + const plotH = HEIGHT - PAD.top - PAD.bottom; + const max = niceMax(Math.max(...years.map((d) => d.total))); + const scale = (v) => (v / max) * plotH; + const base = PAD.top + plotH; + const band = plotW / years.length; + const colW = Math.min(COLUMN_MAX, band - 4); + const peak = years.reduce((a, b) => (b.total > a.total ? b : a)); + const labelEvery = Math.ceil(years.length / 12); + + return ( +No start dates recorded for this selection.
; - - const first = data[0].year; - const last = data[data.length - 1].year; - const byYear = Object.fromEntries(data.map((d) => [d.year, d.count])); - const years = Array.from({ length: last - first + 1 }, (_, i) => first + i) - .map((year) => ({ year, count: byYear[year] || 0 })); - - const width = Math.max(years.length * 28 + PAD.left + PAD.right, 320); - const plotW = width - PAD.left - PAD.right; - const plotH = HEIGHT - PAD.top - PAD.bottom; - const max = niceMax(Math.max(...years.map((d) => d.count))); - const band = plotW / years.length; - const colW = Math.min(COLUMN_MAX, band - 4); - const y = (v) => PAD.top + plotH - (v / max) * plotH; - const ticks = [0, max / 2, max]; - const peak = years.reduce((a, b) => (b.count > a.count ? b : a)); - const labelEvery = Math.ceil(years.length / 12); - - return ( -{unknown.toLocaleString()} projects have no start date and are not shown.
- )} -| Start year | Projects |
|---|---|
| {d.year} | {d.count.toLocaleString()} |
You need the assign-role permission to review account requests.
+People who asked for an account on the sign-up page. Approving gives them the chosen role on this site.
+Loading…
+ ) : requests.length === 0 ? ( +{status === 'pending' ? 'No requests waiting.' : 'None.'}
+{r.registration_note}} +
Loading map…
} +{block.text}
+ : ; + } + const Tag = type; + return+ The NCCRD server (API and database code) is free software, copyright © 2025 South African Environmental + Observation Network (SAEON). You can redistribute it and/or modify it under the terms of the GNU Affero + General Public License as published by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. +
++ It is distributed in the hope that it will be useful, but without any warranty; without even the implied + warranty of merchantability or fitness for a particular purpose. See the GNU Affero General Public License + for more details. +
+Project data published on this website is subject to the Terms of Use.
+ > +); + +const PAGES = { + about: { title: 'About the NCCRD' }, + 'terms-of-use': { title: 'Terms of Use' }, + 'paia-popia': { + title: 'PAIA & POPIA', + subtitle: 'Promotion of Access to Information Act (PAIA) and Protection of Personal Information Act (POPIA)', + extra: ( + <> ++ This website does not use cookies or visitor tracking. When you log in, your session is kept in your + browser’s local storage on your own device, along with any unsaved drafts of a project you are + capturing. Logging out removes the session; a draft stays until you save it or discard it. +
+ > + ), + }, + license: { title: 'Licence', content:{subtitle}
} + {content ?? INFO_PAGES[page].map((block, i) =>- Back to home + No account yet? Request one · Back to home
{done}
+Go to log in
++ You need an account to submit projects. An administrator reviews each request; you can log in once yours is approved. +
+ ++ Already have an account? Log in +
+{subtitle}
} {children} + {csv && ( + + )}{summary.under_way_unknown.toLocaleString()} projects have no start date and are not shown.
+ )} +You need the reviewer permission (validate-submission) to see the review queue.
++ Open a project to read it in full, then accept it to publish it, or mark it not accepted with a reason for the submitter. +
+Loading…
+ ) : items.length === 0 ? ( +Nothing here. {tab === 'awaiting_review' && 'The queue is clear.'}
+You don't have permission to {isEdit ? 'edit' : 'create'} submissions.
+{isEdit ? 'You can only edit your own submissions.' : 'You don’t have permission to create submissions.'}