Skip to content

Commit 4c4b82f

Browse files
Split admin / recovery center into its own page
1 parent 2fd756c commit 4c4b82f

8 files changed

Lines changed: 326 additions & 168 deletions

File tree

nixos/admin-app/app.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,17 +1230,24 @@ def system_page():
12301230
)
12311231

12321232

1233-
@app.route("/box/maintenance")
1233+
@app.route("/box/recovery")
12341234
@login_required
1235-
def maintenance_page():
1235+
def recovery_page():
12361236
return _render_admin_page(
1237-
"maintenance.html",
1238-
page_key="maintenance",
1239-
page_title="Maintenance",
1237+
"recovery.html",
1238+
page_key="recovery",
1239+
page_title="Recovery Center",
1240+
page_eyebrow="Safety And Recovery",
12401241
page_intro="Create encrypted recovery archives, validate restores before applying them, and schedule protected backups to local or attached storage.",
12411242
)
12421243

12431244

1245+
@app.route("/box/maintenance")
1246+
@login_required
1247+
def maintenance_page():
1248+
return redirect(url_for("system_page"))
1249+
1250+
12441251
@app.route("/box/advanced")
12451252
@login_required
12461253
def advanced_page():
@@ -1258,6 +1265,7 @@ def _render_admin_page(
12581265
*,
12591266
page_key: str,
12601267
page_title: str,
1268+
page_eyebrow: str = "",
12611269
page_intro: str = "",
12621270
include_tunnel_status: bool = False,
12631271
**context,
@@ -1272,6 +1280,7 @@ def _render_admin_page(
12721280
dev_mode=DEV_MODE,
12731281
active_page=page_key,
12741282
page_title=page_title,
1283+
page_eyebrow=page_eyebrow,
12751284
page_intro=page_intro,
12761285
version=get_current_version(),
12771286
initial_tunnel_status=initial_tunnel_status,
@@ -1646,7 +1655,7 @@ def api_db_info():
16461655
@login_required
16471656
def api_db_backup():
16481657
return _json_error(
1649-
"Database-only backups were replaced by encrypted Recovery Center backups. Use /box/maintenance.",
1658+
"Database-only backups were replaced by encrypted Recovery Center backups. Use /box/recovery.",
16501659
410,
16511660
)
16521661

@@ -1655,7 +1664,7 @@ def api_db_backup():
16551664
@login_required
16561665
def api_db_restore():
16571666
return _json_error(
1658-
"Database-only restore was replaced by encrypted Recovery Center restore. Use /box/maintenance.",
1667+
"Database-only restore was replaced by encrypted Recovery Center restore. Use /box/recovery.",
16591668
410,
16601669
)
16611670

nixos/admin-app/static/css/admin.css

Lines changed: 155 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,93 +1610,99 @@ input:focus {
16101610
padding: 1.25rem;
16111611
}
16121612

1613+
.admin-page-eyebrow {
1614+
color: rgb(var(--ln-muted));
1615+
font-family: 'JetBrains Mono', monospace;
1616+
font-size: 0.72rem;
1617+
text-transform: uppercase;
1618+
letter-spacing: 0.24em;
1619+
margin-bottom: 0.65rem;
1620+
}
1621+
16131622
.admin-page-actions {
16141623
display: flex;
16151624
flex-wrap: wrap;
16161625
gap: 0.75rem;
16171626
margin-top: 1rem;
16181627
}
16191628

1620-
.recovery-center {
1621-
background:
1622-
radial-gradient(circle at top right, rgb(var(--ln-pink) / 0.06), transparent 28%),
1623-
linear-gradient(180deg, rgb(var(--ln-card)) 0%, rgb(var(--ln-surface)) 100%);
1624-
}
1625-
1626-
.recovery-hero {
1627-
display: flex;
1628-
align-items: flex-start;
1629-
justify-content: space-between;
1630-
gap: 1rem;
1631-
padding-bottom: 1.25rem;
1632-
margin-bottom: 1.25rem;
1633-
border-bottom: 1px solid rgb(var(--ln-border));
1634-
}
1635-
1636-
.recovery-hero-main {
1637-
display: flex;
1638-
align-items: flex-start;
1629+
.recovery-page-header-grid {
1630+
display: grid;
16391631
gap: 1rem;
1640-
min-width: 0;
1632+
margin-top: 1rem;
16411633
}
16421634

1643-
.recovery-hero-icon {
1635+
.recovery-page-meta {
16441636
display: inline-flex;
1645-
align-items: center;
1646-
justify-content: center;
1647-
width: 3rem;
1648-
height: 3rem;
1637+
flex-direction: column;
1638+
align-items: flex-start;
1639+
gap: 0.25rem;
1640+
padding: 0.9rem 1rem;
16491641
border-radius: 1rem;
1650-
background: rgb(var(--ln-pink) / 0.12);
1651-
border: 1px solid rgb(var(--ln-pink) / 0.2);
1652-
color: rgb(var(--ln-pink));
1653-
flex-shrink: 0;
1642+
border: 1px solid rgb(var(--ln-border));
1643+
background: rgb(var(--ln-surface));
1644+
max-width: 14rem;
16541645
}
16551646

1656-
.recovery-hero-icon svg {
1657-
width: 1.4rem;
1658-
height: 1.4rem;
1647+
.recovery-page-meta-label {
1648+
color: rgb(var(--ln-muted));
1649+
font-family: 'JetBrains Mono', monospace;
1650+
font-size: 0.68rem;
1651+
text-transform: uppercase;
1652+
letter-spacing: 0.12em;
16591653
}
16601654

1661-
.recovery-hero-title {
1662-
font-family: 'Sora', sans-serif;
1663-
font-size: 1.45rem;
1664-
font-weight: 700;
1655+
.recovery-page-meta-value {
16651656
color: rgb(var(--ln-text));
1666-
margin: 0 0 0.35rem;
1657+
font-family: 'JetBrains Mono', monospace;
1658+
font-size: 0.92rem;
1659+
line-height: 1.5;
16671660
}
16681661

1669-
.recovery-hero-copy {
1670-
margin: 0;
1671-
max-width: 44rem;
1672-
color: rgb(var(--ln-muted));
1673-
font-size: 0.96rem;
1662+
.recovery-header-actions {
1663+
display: grid;
1664+
grid-template-columns: repeat(3, minmax(0, 1fr));
1665+
gap: 0.85rem;
16741666
}
16751667

1676-
.recovery-hero-meta {
1668+
.recovery-header-card {
16771669
display: flex;
16781670
flex-direction: column;
1679-
align-items: flex-end;
1680-
gap: 0.2rem;
1681-
padding: 0.8rem 0.95rem;
1682-
border-radius: 0.95rem;
1671+
gap: 0.4rem;
1672+
padding: 1rem 1.05rem;
1673+
border-radius: 1rem;
16831674
border: 1px solid rgb(var(--ln-border));
1684-
background: rgb(var(--ln-card) / 0.9);
1685-
min-width: 10rem;
1675+
background:
1676+
radial-gradient(circle at top right, rgb(var(--ln-pink) / 0.08), transparent 38%),
1677+
rgb(var(--ln-surface));
1678+
transition: border-color 0.2s ease, transform 0.2s ease, color 0.2s ease;
16861679
}
16871680

1688-
.recovery-hero-meta-label {
1689-
color: rgb(var(--ln-muted));
1690-
font-family: 'JetBrains Mono', monospace;
1691-
font-size: 0.68rem;
1692-
text-transform: uppercase;
1693-
letter-spacing: 0.12em;
1681+
.recovery-header-card:hover {
1682+
border-color: rgb(var(--ln-pink) / 0.35);
1683+
color: rgb(var(--ln-pink));
1684+
transform: translateY(-1px);
16941685
}
16951686

1696-
.recovery-hero-meta-value {
1687+
.recovery-header-card-label {
16971688
color: rgb(var(--ln-text));
16981689
font-family: 'JetBrains Mono', monospace;
1699-
font-size: 0.84rem;
1690+
font-size: 0.82rem;
1691+
font-weight: 600;
1692+
text-transform: uppercase;
1693+
letter-spacing: 0.08em;
1694+
}
1695+
1696+
.recovery-header-card-copy {
1697+
color: rgb(var(--ln-muted));
1698+
font-size: 0.86rem;
1699+
line-height: 1.5;
1700+
}
1701+
1702+
.recovery-center {
1703+
background:
1704+
radial-gradient(circle at top right, rgb(var(--ln-pink) / 0.06), transparent 28%),
1705+
linear-gradient(180deg, rgb(var(--ln-card)) 0%, rgb(var(--ln-surface)) 100%);
17001706
}
17011707

17021708
.recovery-status-strip {
@@ -1765,42 +1771,51 @@ input:focus {
17651771
}
17661772

17671773
.recovery-accordion-summary {
1768-
list-style: none;
1769-
cursor: pointer;
17701774
display: flex;
17711775
align-items: flex-start;
17721776
justify-content: space-between;
17731777
gap: 1rem;
17741778
padding: 1.1rem 1.15rem;
1779+
border-bottom: 1px solid rgb(var(--ln-border));
17751780
}
17761781

1777-
.recovery-accordion-summary::-webkit-details-marker {
1778-
display: none;
1782+
.recovery-step-heading {
1783+
display: grid;
1784+
grid-template-columns: auto 1fr;
1785+
gap: 0.9rem;
1786+
align-items: start;
1787+
min-width: 0;
1788+
flex: 1 1 auto;
17791789
}
17801790

1781-
.recovery-accordion-summary::after {
1782-
content: "+";
1783-
margin-left: auto;
1784-
color: rgb(var(--ln-muted));
1785-
font-family: 'JetBrains Mono', monospace;
1786-
font-size: 1.1rem;
1787-
line-height: 1;
1791+
.recovery-step-text {
1792+
min-width: 0;
17881793
}
17891794

1790-
.recovery-accordion[open] .recovery-accordion-summary {
1791-
border-bottom: 1px solid rgb(var(--ln-border));
1795+
.recovery-step-icon {
1796+
display: inline-flex;
1797+
align-items: center;
1798+
justify-content: center;
1799+
width: 2.75rem;
1800+
height: 2.75rem;
1801+
border-radius: 0.95rem;
1802+
border: 1px solid rgb(var(--ln-pink) / 0.22);
1803+
background: rgb(var(--ln-pink) / 0.1);
1804+
color: rgb(var(--ln-pink));
1805+
flex-shrink: 0;
17921806
}
17931807

1794-
.recovery-accordion[open] .recovery-accordion-summary::after {
1795-
content: "-";
1796-
color: rgb(var(--ln-pink));
1808+
.recovery-step-icon svg {
1809+
width: 1.2rem;
1810+
height: 1.2rem;
17971811
}
17981812

17991813
.recovery-step-title {
18001814
color: rgb(var(--ln-text));
1801-
font-size: 1rem;
1802-
font-weight: 600;
1803-
margin-top: 0.2rem;
1815+
font-size: 1.08rem;
1816+
font-weight: 700;
1817+
line-height: 1.3;
1818+
margin-top: 0.22rem;
18041819
}
18051820

18061821
.recovery-step-copy {
@@ -1815,6 +1830,7 @@ input:focus {
18151830
align-items: center;
18161831
gap: 0.6rem;
18171832
padding-right: 1.25rem;
1833+
flex-shrink: 0;
18181834
}
18191835

18201836
.recovery-accordion-badge {
@@ -1856,10 +1872,61 @@ input:focus {
18561872
padding: 0.9rem 1rem;
18571873
}
18581874

1875+
.recovery-subsection {
1876+
margin-bottom: 0;
1877+
border: 1px solid rgb(var(--ln-border));
1878+
border-radius: 0.9rem;
1879+
background: rgb(var(--ln-card) / 0.65);
1880+
overflow: hidden;
1881+
}
1882+
1883+
.recovery-subsection-summary {
1884+
list-style: none;
1885+
display: flex;
1886+
align-items: center;
1887+
justify-content: space-between;
1888+
gap: 1rem;
1889+
cursor: pointer;
1890+
padding: 0.9rem 1rem;
1891+
}
1892+
1893+
.recovery-subsection-summary::-webkit-details-marker {
1894+
display: none;
1895+
}
1896+
1897+
.recovery-subsection-summary::after {
1898+
content: "+";
1899+
color: rgb(var(--ln-muted));
1900+
font-family: 'JetBrains Mono', monospace;
1901+
font-size: 1rem;
1902+
line-height: 1;
1903+
}
1904+
1905+
.recovery-subsection[open] .recovery-subsection-summary {
1906+
border-bottom: 1px solid rgb(var(--ln-border));
1907+
}
1908+
1909+
.recovery-subsection[open] .recovery-subsection-summary::after {
1910+
content: "-";
1911+
color: rgb(var(--ln-pink));
1912+
}
1913+
1914+
.recovery-subsection-meta {
1915+
margin-left: auto;
1916+
color: rgb(var(--ln-muted));
1917+
font-family: 'JetBrains Mono', monospace;
1918+
font-size: 0.74rem;
1919+
text-transform: uppercase;
1920+
letter-spacing: 0.08em;
1921+
}
1922+
1923+
.recovery-subsection-body {
1924+
padding: 0.9rem 1rem;
1925+
}
1926+
18591927
.recovery-saved-list {
18601928
display: grid;
18611929
gap: 0.7rem;
1862-
margin-top: 0.85rem;
18631930
}
18641931

18651932
.recovery-saved-row {
@@ -1885,15 +1952,21 @@ input:focus {
18851952
}
18861953

18871954
@media (max-width: 959px) {
1888-
.recovery-hero,
1955+
.recovery-page-meta {
1956+
max-width: none;
1957+
width: 100%;
1958+
}
1959+
1960+
.recovery-header-actions {
1961+
grid-template-columns: 1fr;
1962+
}
1963+
18891964
.recovery-accordion-summary {
18901965
flex-direction: column;
18911966
}
18921967

1893-
.recovery-hero-meta {
1894-
align-items: flex-start;
1895-
width: 100%;
1896-
min-width: 0;
1968+
.recovery-step-heading {
1969+
grid-template-columns: 1fr;
18971970
}
18981971

18991972
.recovery-status-strip,

0 commit comments

Comments
 (0)