mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 23:02:10 +03:00
The dashboard loaded the Material Symbols icon font only from the Google Fonts CDN (fonts.googleapis.com). On networks where that CDN is blocked (e.g. mainland China) the ligature font never loaded, so every icon rendered as its literal text name and the layout broke. Bundle the font locally via the material-symbols package so icons render without a runtime CDN dependency. Closes #3695
This commit is contained in:
committed by
GitHub
parent
da58330845
commit
d8b6ae3688
@@ -8,6 +8,8 @@
|
||||
|
||||
### 🐛 Fixed
|
||||
|
||||
- fix(dashboard): self-host the Material Symbols icon font instead of loading it from the Google Fonts CDN. On networks where `fonts.googleapis.com` is unreachable (e.g. mainland China), the icon ligature font never loaded, so every icon rendered as its literal text name (`smart_toy`, `visibility`, …) and the layout broke — especially after importing many models. The font is now bundled locally via the `material-symbols` package (`@import "material-symbols/outlined.css"` in `globals.css`), removing the runtime CDN dependency. ([#3695](https://github.com/diegosouzapw/OmniRoute/issues/3695) — thanks @lqyiwwx)
|
||||
|
||||
- fix(antigravity): skip Google One AI credits retry on `full_quota_exhausted` verdict — antigravity executor now calls `decide429()` before attempting the credits retry so that a quota-exhausted account (24h cooldown) bypasses the extra upstream HTTP call instead of hanging for up to ~41s. Also persists the cooldown in the DB via `setConnectionRateLimitUntil` so post-restart routing skips exhausted connections without re-learning the hard way. Bonus: `antigravity429Engine` now recognises the real Antigravity "Individual quota reached. Contact your administrator to enable overages." error message as `quota_exhausted`. ([#3707](https://github.com/diegosouzapw/OmniRoute/issues/3707) — thanks @andrea-kingautomation)
|
||||
|
||||
- fix(cli): `ServerSupervisor.handleExit` now coerces the exit code to a number before calling `process.exit()` — Node.js v24 throws `TypeError [ERR_INVALID_ARG_TYPE]` when `process.exit()` receives a string (e.g. `'ENOENT'` from a spawn `error` event's `err.code`). The `error` callback also now passes `-1` instead of the raw `err.code`, which is an OS error string rather than a meaningful exit code. ([#3748](https://github.com/diegosouzapw/OmniRoute/issues/3748))
|
||||
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -50,6 +50,7 @@
|
||||
"lucide-react": "^1.16.0",
|
||||
"marked": "^18.0.4",
|
||||
"marked-terminal": "^7.3.0",
|
||||
"material-symbols": "^0.45.1",
|
||||
"mermaid": "^11.15.0",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"next": "^16.2.6",
|
||||
@@ -93,7 +94,7 @@
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@types/bcryptjs": "^3.0.0",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/bun": "*",
|
||||
"@types/bun": "latest",
|
||||
"@types/keytar": "^4.4.2",
|
||||
"@types/node": "^25.9.1",
|
||||
"@types/react": "^19.2.15",
|
||||
@@ -14876,6 +14877,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/material-symbols": {
|
||||
"version": "0.45.1",
|
||||
"resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.45.1.tgz",
|
||||
"integrity": "sha512-iQibeoKymxHthNqTjYg/jCN2pRySFQ+DAD0sYK9FS7rUpf38i1qR3N4I1jfi/bLS5qdEKvkkJAvf2mE89amSZw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
|
||||
@@ -201,6 +201,7 @@
|
||||
"lucide-react": "^1.16.0",
|
||||
"marked": "^18.0.4",
|
||||
"marked-terminal": "^7.3.0",
|
||||
"material-symbols": "^0.45.1",
|
||||
"mermaid": "^11.15.0",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"next": "^16.2.6",
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
@import "tailwindcss";
|
||||
@import "fumadocs-ui/css/neutral.css";
|
||||
@import "fumadocs-ui/css/preset.css";
|
||||
/* Self-hosted Material Symbols icon font (#3695): the Google Fonts CDN
|
||||
(fonts.googleapis.com) is blocked in some networks (e.g. mainland China),
|
||||
which made every icon ligature fall back to its literal text name and broke
|
||||
the layout. Bundling the font locally removes that runtime CDN dependency.
|
||||
The bundled @font-face uses family "Material Symbols Outlined", matching the
|
||||
.material-symbols-outlined rule defined later in this file. */
|
||||
@import "material-symbols/outlined.css";
|
||||
@source "../../node_modules/fumadocs-ui/css/generated/*.css";
|
||||
|
||||
/* Tailwind v4 auto-detection cannot scan directories with parentheses
|
||||
|
||||
@@ -59,13 +59,9 @@ export default async function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang={locale} dir={isRtl ? "rtl" : "ltr"} suppressHydrationWarning>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||
{/* eslint-disable-next-line @next/next/no-page-custom-font */}
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
{/* Material Symbols icon font is self-hosted via globals.css
|
||||
(@import "material-symbols/outlined.css") so icons render even when
|
||||
the Google Fonts CDN is unreachable (#3695). */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
|
||||
58
tests/unit/dashboard/material-icons-self-hosted.test.ts
Normal file
58
tests/unit/dashboard/material-icons-self-hosted.test.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { resolve, join } from "node:path";
|
||||
|
||||
// Regression guard for #3695: the dashboard icons turned into their literal
|
||||
// text names ("smart_toy", "visibility", ...) and the layout broke for users
|
||||
// on networks where the Google Fonts CDN (fonts.googleapis.com / fonts.gstatic.com)
|
||||
// is unreachable — e.g. mainland China. Root cause: the Material Symbols icon
|
||||
// font (the sole source of the .material-symbols-outlined @font-face) was loaded
|
||||
// only from that CDN in src/app/layout.tsx. The fix self-hosts the font via the
|
||||
// `material-symbols` npm package imported in globals.css. These assertions fail
|
||||
// on the pre-fix tree and stay green afterwards, preventing re-introduction of a
|
||||
// runtime CDN dependency for icons.
|
||||
|
||||
const cwd = process.cwd();
|
||||
const layoutPath = resolve(join(cwd, "src/app/layout.tsx"));
|
||||
const globalsPath = resolve(join(cwd, "src/app/globals.css"));
|
||||
|
||||
test("layout.tsx does not load the Material Symbols icon font from the Google Fonts CDN", () => {
|
||||
const layout = readFileSync(layoutPath, "utf8");
|
||||
assert.ok(
|
||||
!/fonts\.googleapis\.com[^"'\s]*Material\+Symbols/i.test(layout),
|
||||
"layout.tsx must not load Material Symbols from fonts.googleapis.com (blocked in some regions)"
|
||||
);
|
||||
assert.ok(
|
||||
!/fonts\.gstatic\.com/.test(layout),
|
||||
"layout.tsx must not preconnect to the Google Fonts CDN for the icon font"
|
||||
);
|
||||
});
|
||||
|
||||
test("globals.css imports the self-hosted Material Symbols font", () => {
|
||||
const globals = readFileSync(globalsPath, "utf8");
|
||||
assert.match(
|
||||
globals,
|
||||
/@import\s+["']material-symbols\/outlined\.css["']/,
|
||||
"globals.css must @import the self-hosted material-symbols/outlined.css"
|
||||
);
|
||||
});
|
||||
|
||||
test("the self-hosted material-symbols package is declared and resolvable", () => {
|
||||
const pkg = JSON.parse(readFileSync(resolve(join(cwd, "package.json")), "utf8")) as {
|
||||
dependencies?: Record<string, string>;
|
||||
};
|
||||
assert.ok(
|
||||
pkg.dependencies?.["material-symbols"],
|
||||
"package.json must declare the material-symbols dependency"
|
||||
);
|
||||
// The bundled CSS that supplies the @font-face + woff2 must exist on disk so the
|
||||
// build can inline it (only enforced when node_modules is installed).
|
||||
const cssPath = resolve(join(cwd, "node_modules/material-symbols/outlined.css"));
|
||||
if (existsSync(resolve(join(cwd, "node_modules/material-symbols")))) {
|
||||
assert.ok(
|
||||
existsSync(cssPath),
|
||||
"material-symbols/outlined.css must exist in the installed package"
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user