155 lines
6.2 KiB
Markdown
155 lines
6.2 KiB
Markdown
|
|
---
|
||
|
|
title: Interface Changes
|
||
|
|
---
|
||
|
|
|
||
|
|
```js
|
||
|
|
import {API} from "./components/config.js";
|
||
|
|
```
|
||
|
|
|
||
|
|
```js
|
||
|
|
const [published, draft, repos] = await Promise.all([
|
||
|
|
fetch(`${API}/interface-changes/?status=published`).then(r => r.ok ? r.json() : []),
|
||
|
|
fetch(`${API}/interface-changes/?status=draft`).then(r => r.ok ? r.json() : []),
|
||
|
|
fetch(`${API}/repos/`).then(r => r.ok ? r.json() : []),
|
||
|
|
]);
|
||
|
|
```
|
||
|
|
|
||
|
|
```js
|
||
|
|
const repoMap = Object.fromEntries(repos.map(r => [r.slug, r]));
|
||
|
|
|
||
|
|
const CHANGE_TYPE_COLOR = {
|
||
|
|
breaking: "#ef4444",
|
||
|
|
removal: "#f97316",
|
||
|
|
deprecation: "#f59e0b",
|
||
|
|
additive: "#22c55e",
|
||
|
|
};
|
||
|
|
|
||
|
|
function changeBadge(type) {
|
||
|
|
const color = CHANGE_TYPE_COLOR[type] ?? "#6b7280";
|
||
|
|
return htl.html`<span style="
|
||
|
|
background:${color};color:#fff;font-size:11px;font-weight:700;
|
||
|
|
padding:2px 7px;border-radius:10px;text-transform:uppercase;letter-spacing:.04em
|
||
|
|
">${type}</span>`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function interfaceBadge(type) {
|
||
|
|
return htl.html`<span style="
|
||
|
|
background:#3b82f6;color:#fff;font-size:10px;font-weight:600;
|
||
|
|
padding:1px 6px;border-radius:8px
|
||
|
|
">${type}</span>`;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
# Interface Changes
|
||
|
|
|
||
|
|
Track breaking and additive mutations to published interfaces across repos.
|
||
|
|
Publishing a change sends inbox notifications to all affected agents.
|
||
|
|
|
||
|
|
<div style="display:flex;gap:16px;margin-bottom:24px">
|
||
|
|
<div style="background:#fef2f2;border:1px solid #fca5a5;border-radius:8px;padding:12px 20px;text-align:center">
|
||
|
|
<div style="font-size:28px;font-weight:700;color:#dc2626">${published.filter(c => c.change_type === "breaking").length}</div>
|
||
|
|
<div style="font-size:12px;color:#6b7280">Breaking (live)</div>
|
||
|
|
</div>
|
||
|
|
<div style="background:#fff7ed;border:1px solid #fdba74;border-radius:8px;padding:12px 20px;text-align:center">
|
||
|
|
<div style="font-size:28px;font-weight:700;color:#ea580c">${published.filter(c => c.change_type === "deprecation").length}</div>
|
||
|
|
<div style="font-size:12px;color:#6b7280">Deprecations (live)</div>
|
||
|
|
</div>
|
||
|
|
<div style="background:#f0fdf4;border:1px solid #86efac;border-radius:8px;padding:12px 20px;text-align:center">
|
||
|
|
<div style="font-size:28px;font-weight:700;color:#16a34a">${published.filter(c => c.change_type === "additive").length}</div>
|
||
|
|
<div style="font-size:12px;color:#6b7280">Additive (live)</div>
|
||
|
|
</div>
|
||
|
|
<div style="background:#f9fafb;border:1px solid #d1d5db;border-radius:8px;padding:12px 20px;text-align:center">
|
||
|
|
<div style="font-size:28px;font-weight:700;color:#374151">${draft.length}</div>
|
||
|
|
<div style="font-size:12px;color:#6b7280">Drafts</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
## Planned changes
|
||
|
|
|
||
|
|
```js
|
||
|
|
const planned = [...published, ...draft].filter(c => c.planned_for);
|
||
|
|
planned.sort((a, b) => a.planned_for.localeCompare(b.planned_for));
|
||
|
|
```
|
||
|
|
|
||
|
|
```js
|
||
|
|
if (planned.length === 0) {
|
||
|
|
display(htl.html`<p style="color:#6b7280;font-style:italic">No changes with a planned date.</p>`);
|
||
|
|
} else {
|
||
|
|
display(htl.html`<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||
|
|
<thead><tr style="border-bottom:2px solid #e5e7eb">
|
||
|
|
<th style="text-align:left;padding:6px 8px">Date</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Change</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Repo</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Status</th>
|
||
|
|
</tr></thead>
|
||
|
|
<tbody>
|
||
|
|
${planned.map(c => htl.html`<tr style="border-bottom:1px solid #f3f4f6">
|
||
|
|
<td style="padding:6px 8px;white-space:nowrap;color:#374151">${c.planned_for}</td>
|
||
|
|
<td style="padding:6px 8px">${changeBadge(c.change_type)} ${c.title}</td>
|
||
|
|
<td style="padding:6px 8px;color:#6b7280">${c.origin_repo_slug ?? c.repo_slug}</td>
|
||
|
|
<td style="padding:6px 8px">${c.status}</td>
|
||
|
|
</tr>`)}
|
||
|
|
</tbody>
|
||
|
|
</table>`);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Published changes
|
||
|
|
|
||
|
|
```js
|
||
|
|
if (published.length === 0) {
|
||
|
|
display(htl.html`<p style="color:#6b7280;font-style:italic">No published changes.</p>`);
|
||
|
|
} else {
|
||
|
|
display(htl.html`<div style="display:flex;flex-direction:column;gap:12px">
|
||
|
|
${published.map(c => htl.html`
|
||
|
|
<div style="border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px">
|
||
|
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;flex-wrap:wrap">
|
||
|
|
${changeBadge(c.change_type)}
|
||
|
|
${interfaceBadge(c.interface_type)}
|
||
|
|
<strong style="font-size:14px">${c.title}</strong>
|
||
|
|
</div>
|
||
|
|
<div style="font-size:12px;color:#6b7280;margin-bottom:6px">
|
||
|
|
Repo: <strong>${c.origin_repo_slug ?? c.repo_slug}</strong>
|
||
|
|
${c.published_at ? htl.html` · Published ${c.published_at.slice(0,10)}` : ""}
|
||
|
|
${c.affected_repo_slugs?.length ? htl.html` · Affects: ${c.affected_repo_slugs.join(", ")}` : ""}
|
||
|
|
</div>
|
||
|
|
<details style="font-size:13px;color:#374151">
|
||
|
|
<summary style="cursor:pointer;color:#6b7280">Description</summary>
|
||
|
|
<pre style="margin-top:6px;white-space:pre-wrap;font-family:inherit">${c.description}</pre>
|
||
|
|
</details>
|
||
|
|
${c.affected_paths?.length ? htl.html`
|
||
|
|
<div style="margin-top:6px;font-size:12px">
|
||
|
|
<strong>Paths:</strong>
|
||
|
|
${c.affected_paths.map(p => htl.html`<code style="background:#f3f4f6;padding:1px 5px;border-radius:4px;margin:0 2px">${p}</code>`)}
|
||
|
|
</div>` : ""}
|
||
|
|
</div>
|
||
|
|
`)}
|
||
|
|
</div>`);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Drafts
|
||
|
|
|
||
|
|
```js
|
||
|
|
if (draft.length === 0) {
|
||
|
|
display(htl.html`<p style="color:#6b7280;font-style:italic">No draft changes.</p>`);
|
||
|
|
} else {
|
||
|
|
display(htl.html`<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||
|
|
<thead><tr style="border-bottom:2px solid #e5e7eb">
|
||
|
|
<th style="text-align:left;padding:6px 8px">Title</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Repo</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Type</th>
|
||
|
|
<th style="text-align:left;padding:6px 8px">Affected</th>
|
||
|
|
</tr></thead>
|
||
|
|
<tbody>
|
||
|
|
${draft.map(c => htl.html`<tr style="border-bottom:1px solid #f3f4f6">
|
||
|
|
<td style="padding:6px 8px">${c.title}</td>
|
||
|
|
<td style="padding:6px 8px;color:#6b7280">${c.repo_slug}</td>
|
||
|
|
<td style="padding:6px 8px">${changeBadge(c.change_type)} ${interfaceBadge(c.interface_type)}</td>
|
||
|
|
<td style="padding:6px 8px;color:#6b7280">${(c.affected_repo_slugs ?? []).join(", ") || "—"}</td>
|
||
|
|
</tr>`)}
|
||
|
|
</tbody>
|
||
|
|
</table>`);
|
||
|
|
}
|
||
|
|
```
|