<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Deployment Records</title>
<style>
:root {
color-scheme: light;
--page: #f3f4f6;
--surface: #ffffff;
--border: #dfe3e8;
--border-soft: #e8ebef;
--text: #20242b;
--muted: #68707d;
--subtle: #8a929e;
--header: #f7f8fa;
--hover: #f5f7f9;
--selected: #edf5ff;
--selected-border: #2f6fbd;
--green: #237a4b;
--green-bg: #ebf7f0;
--blue: #2468a9;
--blue-bg: #edf5fc;
--red: #b33a3a;
--red-bg: #fceeee;
--amber: #986b12;
--amber-bg: #fff6df;
--gray: #606975;
--gray-bg: #f0f2f4;
--purple: #7150a5;
--purple-bg: #f3eefb;
--shadow: 0 1px 2px rgba(18, 25, 38, 0.04);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-width: 1120px;
min-height: 100vh;
padding: 64px;
background: var(--page);
color: var(--text);
font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-size: 13px;
-webkit-font-smoothing: antialiased;
}
.table-card {
width: 1100px;
margin: 0 auto;
overflow: hidden;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: var(--shadow);
}
.table-toolbar {
height: 58px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 18px;
border-bottom: 1px solid var(--border);
}
.title-group {
display: flex;
align-items: baseline;
gap: 9px;
}
h1 {
margin: 0;
font-size: 15px;
font-weight: 650;
letter-spacing: -0.01em;
}
.record-count {
color: var(--muted);
font-size: 12px;
}
.environment {
display: inline-flex;
align-items: center;
gap: 7px;
height: 28px;
padding: 0 10px;
color: #454d58;
background: #fafbfc;
border: 1px solid var(--border);
border-radius: 5px;
font-size: 12px;
font-weight: 550;
}
.environment-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: #237a4b;
box-shadow: 0 0 0 2px #e1f2e8;
}
.table-wrap {
overflow: hidden;
}
table {
width: 100%;
border-spacing: 0;
border-collapse: separate;
table-layout: fixed;
}
col.status { width: 150px; }
col.service { width: 220px; }
col.region { width: 154px; }
col.actor { width: 190px; }
col.duration { width: 112px; }
col.timestamp { width: 274px; }
thead th {
height: 38px;
padding: 0 14px;
color: #606975;
background: var(--header);
border-bottom: 1px solid var(--border);
text-align: left;
font-size: 11px;
font-weight: 650;
letter-spacing: 0.025em;
text-transform: uppercase;
white-space: nowrap;
}
thead th:first-child,
tbody td:first-child {
padding-left: 18px;
}
thead th:last-child,
tbody td:last-child {
padding-right: 18px;
}
.sort-button {
width: calc(100% + 12px);
height: 30px;
margin-left: -6px;
padding: 0 6px;
display: flex;
align-items: center;
gap: 6px;
color: #39414c;
background: transparent;
border: 0;
border-radius: 4px;
font: inherit;
font-weight: 700;
letter-spacing: inherit;
text-transform: inherit;
cursor: pointer;
}
.sort-button:hover {
background: #eceff2;
}
.sort-button:focus-visible {
outline: 2px solid #3b78bd;
outline-offset: 1px;
}
.sort-icon {
width: 13px;
height: 13px;
color: var(--selected-border);
transition: transform 140ms ease;
}
.sort-button[data-direction="ascending"] .sort-icon {
transform: rotate(180deg);
}
tbody tr {
position: relative;
background: var(--surface);
transition: background-color 100ms ease;
cursor: default;
}
tbody tr:hover,
tbody tr.is-hovered {
background: var(--hover);
}
tbody tr.is-selected {
background: var(--selected);
}
tbody tr.is-selected:hover {
background: #e7f1fd;
}
tbody td {
height: 52px;
padding: 0 14px;
border-bottom: 1px solid var(--border-soft);
color: #313741;
vertical-align: middle;
white-space: nowrap;
}
tbody tr:last-child td {
border-bottom: 0;
}
tbody tr.is-selected td:first-child {
position: relative;
}
tbody tr.is-selected td:first-child::before {
content: "";
position: absolute;
top: -1px;
bottom: -1px;
left: 0;
width: 3px;
background: var(--selected-border);
}
.status-pill {
display: inline-flex;
align-items: center;
gap: 6px;
min-height: 24px;
padding: 3px 8px 3px 6px;
border: 1px solid transparent;
border-radius: 999px;
font-size: 11.5px;
font-weight: 620;
line-height: 1;
}
.status-icon {
width: 14px;
height: 14px;
flex: 0 0 auto;
}
.succeeded {
color: var(--green);
background: var(--green-bg);
border-color: #d3ebdc;
}
.deploying {
color: var(--blue);
background: var(--blue-bg);
border-color: #d7e7f5;
}
.failed {
color: var(--red);
background: var(--red-bg);
border-color: #f2d5d5;
}
.queued {
color: var(--amber);
background: var(--amber-bg);
border-color: #f1e3b9;
}
.canceled {
color: var(--gray);
background: var(--gray-bg);
border-color: #dde1e5;
}
.rolled-back {
color: var(--purple);
background: var(--purple-bg);
border-color: #e1d7f1;
}
.service-cell {
display: flex;
min-width: 0;
flex-direction: column;
justify-content: center;
gap: 3px;
}
.service-name {
overflow: hidden;
color: #252b33;
font-weight: 620;
text-overflow: ellipsis;
}
.revision {
color: var(--subtle);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 11px;
}
.region-name {
color: #414852;
}
.region-code {
margin-left: 5px;
color: var(--subtle);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 11px;
}
.actor-cell {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.avatar {
width: 24px;
height: 24px;
display: inline-flex;
flex: 0 0 auto;
align-items: center;
justify-content: center;
color: #53606e;
background: #eef1f4;
border: 1px solid #dce1e6;
border-radius: 50%;
font-size: 9px;
font-weight: 750;
letter-spacing: 0.02em;
}
.avatar.bot {
color: #4f6190;
background: #edf0f8;
border-color: #d9deed;
}
.actor-name {
overflow: hidden;
text-overflow: ellipsis;
}
.duration,
time {
color: #515965;
font-variant-numeric: tabular-nums;
}
.table-footer {
height: 42px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 18px;
color: var(--muted);
background: #fafbfc;
border-top: 1px solid var(--border);
font-size: 11.5px;
}
.selection-note {
color: #4f6682;
}
kbd {
min-width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 5px;
padding: 0 5px;
color: #606975;
background: #fff;
border: 1px solid #d8dde3;
border-bottom-color: #c7cdd4;
border-radius: 4px;
box-shadow: 0 1px 0 #dfe3e7;
font-family: inherit;
font-size: 10px;
}
</style>
</head>
<body>
<main class="table-card" aria-labelledby="deployments-title">
<header class="table-toolbar">
<div class="title-group">
<h1 id="deployments-title">Deployments</h1>
<span class="record-count">8 records</span>
</div>
<div class="environment" aria-label="Environment: Production">
<span class="environment-dot" aria-hidden="true"></span>
Production
</div>
</header>
<div class="table-wrap">
<table aria-label="Server deployment records">
<colgroup>
<col class="status">
<col class="service">
<col class="region">
<col class="actor">
<col class="duration">
<col class="timestamp">
</colgroup>
<thead>
<tr>
<th scope="col">Status</th>
<th scope="col">Service name</th>
<th scope="col">Region</th>
<th scope="col">Deployed by</th>
<th scope="col">Duration</th>
<th scope="col" aria-sort="descending">
<button class="sort-button" type="button" data-direction="descending" aria-label="Timestamp, sorted newest first">
Timestamp
<svg class="sort-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M4 6.25 8 10l4-3.75" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</th>
</tr>
</thead>
<tbody>
<tr data-time="2025-06-18T14:42:09Z">
<td>
<span class="status-pill succeeded">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="m5 8.1 1.8 1.8 4.1-4.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Succeeded
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">api-gateway</span>
<span class="revision">a91f2c7</span>
</div>
</td>
<td><span class="region-name">N. Virginia</span><span class="region-code">us-east-1</span></td>
<td>
<div class="actor-cell"><span class="avatar">AM</span><span class="actor-name">Avery Morgan</span></div>
</td>
<td class="duration">2m 14s</td>
<td><time datetime="2025-06-18T14:42:09Z">Jun 18, 2025 14:42:09 UTC</time></td>
</tr>
<tr class="is-hovered" data-time="2025-06-18T14:31:46Z">
<td>
<span class="status-pill deploying">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M8 1.75a6.25 6.25 0 1 1-5.3 2.93" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<path d="M2.15 2.55v2.8h2.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Deploying
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">auth-service</span>
<span class="revision">f207de1</span>
</div>
</td>
<td><span class="region-name">Frankfurt</span><span class="region-code">eu-central-1</span></td>
<td>
<div class="actor-cell"><span class="avatar bot">CI</span><span class="actor-name">release-bot</span></div>
</td>
<td class="duration">1m 08s</td>
<td><time datetime="2025-06-18T14:31:46Z">Jun 18, 2025 14:31:46 UTC</time></td>
</tr>
<tr class="is-selected" aria-selected="true" data-time="2025-06-18T13:58:22Z">
<td>
<span class="status-pill failed">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="M8 4.5v4.2M8 11.25v.15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/>
</svg>
Failed
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">billing-worker</span>
<span class="revision">d84b019</span>
</div>
</td>
<td><span class="region-name">Oregon</span><span class="region-code">us-west-2</span></td>
<td>
<div class="actor-cell"><span class="avatar">JL</span><span class="actor-name">Jordan Lee</span></div>
</td>
<td class="duration">48s</td>
<td><time datetime="2025-06-18T13:58:22Z">Jun 18, 2025 13:58:22 UTC</time></td>
</tr>
<tr data-time="2025-06-18T13:17:04Z">
<td>
<span class="status-pill succeeded">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="m5 8.1 1.8 1.8 4.1-4.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Succeeded
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">event-processor</span>
<span class="revision">4c120ab</span>
</div>
</td>
<td><span class="region-name">Singapore</span><span class="region-code">ap-southeast-1</span></td>
<td>
<div class="actor-cell"><span class="avatar bot">CI</span><span class="actor-name">release-bot</span></div>
</td>
<td class="duration">3m 02s</td>
<td><time datetime="2025-06-18T13:17:04Z">Jun 18, 2025 13:17:04 UTC</time></td>
</tr>
<tr data-time="2025-06-18T12:46:31Z">
<td>
<span class="status-pill canceled">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="M5.65 5.65 10.35 10.35M10.35 5.65l-4.7 4.7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
Canceled
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">search-indexer</span>
<span class="revision">09bc73e</span>
</div>
</td>
<td><span class="region-name">London</span><span class="region-code">eu-west-2</span></td>
<td>
<div class="actor-cell"><span class="avatar">SP</span><span class="actor-name">Samir Patel</span></div>
</td>
<td class="duration">37s</td>
<td><time datetime="2025-06-18T12:46:31Z">Jun 18, 2025 12:46:31 UTC</time></td>
</tr>
<tr data-time="2025-06-18T11:29:18Z">
<td>
<span class="status-pill succeeded">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="m5 8.1 1.8 1.8 4.1-4.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Succeeded
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">notifications</span>
<span class="revision">ae441cf</span>
</div>
</td>
<td><span class="region-name">Sydney</span><span class="region-code">ap-southeast-2</span></td>
<td>
<div class="actor-cell"><span class="avatar">EC</span><span class="actor-name">Elena Cruz</span></div>
</td>
<td class="duration">1m 51s</td>
<td><time datetime="2025-06-18T11:29:18Z">Jun 18, 2025 11:29:18 UTC</time></td>
</tr>
<tr data-time="2025-06-18T10:54:07Z">
<td>
<span class="status-pill rolled-back">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M5.1 4H2.4V1.3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.65 4.05A6 6 0 1 1 2.2 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
Rolled back
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">media-transformer</span>
<span class="revision">781d6fa</span>
</div>
</td>
<td><span class="region-name">Tokyo</span><span class="region-code">ap-northeast-1</span></td>
<td>
<div class="actor-cell"><span class="avatar bot">OP</span><span class="actor-name">ops-automation</span></div>
</td>
<td class="duration">4m 26s</td>
<td><time datetime="2025-06-18T10:54:07Z">Jun 18, 2025 10:54:07 UTC</time></td>
</tr>
<tr data-time="2025-06-18T10:21:53Z">
<td>
<span class="status-pill queued">
<svg class="status-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/>
<path d="M8 4.4v3.9l2.55 1.45" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Queued
</span>
</td>
<td>
<div class="service-cell">
<span class="service-name">reporting-api</span>
<span class="revision">c536be8</span>
</div>
</td>
<td><span class="region-name">N. Virginia</span><span class="region-code">us-east-1</span></td>
<td>
<div class="actor-cell"><span class="avatar">NK</span><span class="actor-name">Noah Kim</span></div>
</td>
<td class="duration">—</td>
<td><time datetime="2025-06-18T10:21:53Z">Jun 18, 2025 10:21:53 UTC</time></td>
</tr>
</tbody>
</table>
</div>
<footer class="table-footer">
<span>Showing 8 of 8 deployments</span>
<span class="selection-note">1 row selected <kbd>Esc</kbd> to clear</span>
</footer>
</main>
<script>
(() => {
const tbody = document.querySelector("tbody");
const sortButton = document.querySelector(".sort-button");
const sortHeader = sortButton.closest("th");
sortButton.addEventListener("click", () => {
const nextDirection =
sortButton.dataset.direction === "descending" ? "ascending" : "descending";
const rows = Array.from(tbody.querySelectorAll("tr"));
rows.sort((a, b) => {
const aTime = Date.parse(a.dataset.time);
const bTime = Date.parse(b.dataset.time);
return nextDirection === "ascending" ? aTime - bTime : bTime - aTime;
});
rows.forEach(row => tbody.appendChild(row));
sortButton.dataset.direction = nextDirection;
sortHeader.setAttribute("aria-sort", nextDirection);
sortButton.setAttribute(
"aria-label",
`Timestamp, sorted ${nextDirection === "ascending" ? "oldest" : "newest"} first`
);
});
tbody.addEventListener("click", event => {
const row = event.target.closest("tr");
if (!row) return;
tbody.querySelectorAll("tr").forEach(item => {
item.classList.remove("is-selected");
item.removeAttribute("aria-selected");
});
row.classList.add("is-selected");
row.setAttribute("aria-selected", "true");
});
})();
</script>
</body>
</html>