* feat: add an auto or fixed columns picker to card grids

* feat: add safe mode that only runs layout and theme plugins

* docs: add simple layout to plugin table

* fix: ask for local network access in the macOS app

* feat: allow plugin registries on listed private hosts (#1705)

* chore: add private registry hosts to the changelog

* feat: use the proxy for plugin registry downloads

* fix: allow changing connection origin on shared hosts

* chore: update translations and plugin pins

* chore: lint, format, and bump version to 26.10.5

---------

Co-authored-by: Lukas <80832688+0skater0@users.noreply.github.com>
This commit is contained in:
Luke GustafsonandLukas authored and GitHub committed 2026-10-22 13:30:48 -05:00
1 parent 7b7b17e31f
commit 96b8520fb4
96 files changed
+1885 -474

No files matched your search

@@ -102,6 +102,7 @@ beforeEach(async () => {
state.defaultLookIds = [];
state.installed = [];
delete process.env.TERMIX_SAFE_LAYOUT;
delete process.env.TERMIX_SAFE_MODE;
const app = express();
app.use(express.json());
@@ -113,6 +114,7 @@ beforeEach(async () => {
afterEach(async () => {
delete process.env.TERMIX_SAFE_LAYOUT;
delete process.env.TERMIX_SAFE_MODE;
await new Promise<void>((resolve) => server.close(() => resolve()));
});
@@ -138,6 +140,7 @@ describe("GET /user-preferences/look", () => {
defaults: { layout: null, theme: null },
defaultLook: { layout: null, theme: null },
safeLayout: false,
safeMode: false,
unavailable: [],
});
});
@@ -159,6 +162,7 @@ describe("GET /user-preferences/look", () => {
{ id: "other", version: null, layouts: [], themes: [], error: "y" },
];
process.env.TERMIX_SAFE_LAYOUT = "1";
process.env.TERMIX_SAFE_MODE = "1";
const { body } = await getLook();
expect(body).toMatchObject({
@@ -167,6 +171,7 @@ describe("GET /user-preferences/look", () => {
defaults: { layout: "admin-layout", theme: "gruvbox" },
defaultLook: { layout: "shipped", theme: "ink" },
safeLayout: true,
safeMode: true,
});
expect(body.unavailable.map((plugin: { id: string }) => plugin.id)).toEqual(
["broken"],
@@ -488,6 +488,26 @@ describe("plugins route", () => {
}
});
it("reports an enabled plugin that safe mode keeps off", async () => {
state.plugins.set("sample-plugin", makePlugin({ state: "enabled" }));
const read = async () =>
(
(await (await fetch(`${baseUrl}/plugins`)).json()) as Array<{
state: string;
enabled: boolean;
}>
)[0];
expect((await read()).state).not.toBe("safe-mode");
process.env.TERMIX_SAFE_MODE = "1";
try {
expect(await read()).toMatchObject({ state: "safe-mode", enabled: true });
} finally {
delete process.env.TERMIX_SAFE_MODE;
}
});
it("grants a declared capability", async () => {
state.plugins.set("sample-plugin", makePlugin());