---
title: Contributions
---
```js
import {API, apiFetch, pollDelay, waitForVisible} from "./components/config.js";
const POLL = 30_000;
```
```js
// Live poll for contributions
const contribState = (async function*() {
let failures = 0;
while (true) {
let data = [], ok = false;
try {
const r = await apiFetch("/contributions/");
ok = r.ok;
data = ok ? await r.json() : [];
} catch {}
failures = ok ? 0 : failures + 1;
yield {data, ok, ts: new Date()};
await waitForVisible(pollDelay({ok, base: POLL, failures}));
}
})();
```
```js
const contribs = contribState.data ?? [];
const _ok = contribState.ok ?? false;
const _ts = contribState.ts;
```
# Contributions
```js
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
const _liveEl = html`
●
${_ok ? `Live · ${_ts?.toLocaleTimeString()}` : html`API offline`}
`;
withDocHelp(_liveEl, "/docs/live-data");
injectTocTop("live-indicator", _liveEl);
const _h1 = document.querySelector("#observablehq-main h1");
if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/contributions"); }
```
```js
// Filters
const typeFilter = Inputs.select(["all", "br", "fr", "ep", "upr"], {label: "Type", value: "all"});
const statFilter = Inputs.select(
["all", "draft", "submitted", "acknowledged", "accepted", "rejected", "merged", "withdrawn"],
{label: "Status", value: "all"}
);
const repoFilter = Inputs.text({label: "Target repo", placeholder: "filter by repo…"});
display(html`
${typeFilter}${statFilter}${repoFilter}
`);
```
```js
const tf = typeFilter.value;
const sf = statFilter.value;
const rf = repoFilter.value?.trim().toLowerCase() ?? "";
const filtered = contribs.filter(c =>
(tf === "all" || c.type === tf) &&
(sf === "all" || c.status === sf) &&
(!rf || (c.target_repo ?? "").toLowerCase().includes(rf))
);
```
## Summary
```js
const typeLabels = {br: "Bug Report", fr: "Feature Request", ep: "Extension Point", upr: "Upstream PR"};
const typeCounts = Object.fromEntries(["br","fr","ep","upr"].map(t => [
t, contribs.filter(c => c.type === t).length
]));
const needsFollowUp = contribs.filter(c => ["submitted","acknowledged"].includes(c.status)).length;
display(html`
${["br","fr","ep","upr"].map(t => html`
${typeLabels[t]}
${typeCounts[t]}
`)}
${needsFollowUp > 0 ? html`⚠ ${needsFollowUp} contribution(s) awaiting upstream response (submitted / acknowledged)
` : ""}
`);
```
## Status Kanban
```js
const statusCols = [
{key: "draft", label: "Draft", color: "#aaa"},
{key: "submitted", label: "Submitted", color: "steelblue"},
{key: "acknowledged", label: "Acknowledged",color: "#f0a500"},
{key: "accepted", label: "Accepted", color: "#4caf50"},
{key: "merged", label: "Merged", color: "#2e7d32"},
{key: "rejected", label: "Rejected", color: "#e53935"},
{key: "withdrawn", label: "Withdrawn", color: "#bbb"},
];
const colMap = {};
for (const c of filtered) {
(colMap[c.status] = colMap[c.status] ?? []).push(c);
}
const activeCols = statusCols.filter(s => colMap[s.key]?.length);
if (activeCols.length === 0) {
display(html`No contributions match the current filters.
`);
} else {
display(html`
${activeCols.map(s => html`
${colMap[s.key].map(c => html`
${c.type.toUpperCase()}
${c.title}
${c.target_org || c.target_repo ? html`
${[c.target_org, c.target_repo].filter(Boolean).join("/")}
` : ""}
${c.body_path ? html`
${c.body_path}
` : ""}
${new Date(c.created_at).toLocaleDateString()}
`)}
`)}
`);
}
```
## All Contributions
```js
display(Inputs.table(filtered.map(c => ({
Type: c.type.toUpperCase(),
Title: c.title,
Status: c.status,
Target: [c.target_org, c.target_repo].filter(Boolean).join("/") || "—",
Created: new Date(c.created_at).toLocaleDateString(),
})), {maxWidth: 900}));
```