Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# CHANGELOG

## v2.3.1 (25 September 2026)

### Fixes

- Login page shows the Clear and Sign in buttons in one row instead of stacked
- Logging out now renders the login page immediately instead of a page-not-found state
- DNS custom records show a single Add record action in the empty state
- Services page uses the standard page width like other routes

## v2.3.0 (25 September 2026)

### Administration UI
Expand Down
92 changes: 46 additions & 46 deletions application/webserver/frontend/files/fs/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ var GSPROXYPORT = "10413"
var GSWEBADMINPORT = "10786"
var GSBASEDIR = ""
var Baseendpointv2 = "https://www.gatesentryfilter.com/api/"
var GATESENTRY_VERSION = "2.3.0"
var GATESENTRY_VERSION = "2.3.1"
var GS_BOUND_ADDRESS = ":"
var R *application.GSRuntime

Expand Down
7 changes: 6 additions & 1 deletion ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@
</Route>
{:else}
<div class="app-frame">
<Globalheader bind:isSideNavOpen bind:userProfilePanelOpen {pathname} />
<Globalheader
bind:isSideNavOpen
bind:userProfilePanelOpen
{pathname}
on:loggedout={() => (state = "login")}
/>
<SideNav
bind:isOpen={isSideNavOpen}
rail
Expand Down
6 changes: 6 additions & 0 deletions ui/src/components/__tests__/dns_ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ test("custom DNS records preserve endpoint payload and stable edit identity", ()
expect(records).not.toContain('style="float:right;"');
});

test("custom DNS records expose one add-record action, not a duplicate empty-state button", () => {
expect(recordsSource.match(/Add record/g)?.length ?? 0).toBe(1);
expect(recordsSource).toContain('slot="actions"');
expect(recordsSource).toContain("on:click={openCreate}");
});

test("DNS block lists edit by row identity and confirm removal", () => {
const lists = compact(listsSource);
expect(lists).toContain('getSetting("dns_custom_entries")');
Expand Down
12 changes: 12 additions & 0 deletions ui/src/components/__tests__/secure_setup_ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import loginSource from "../../routes/login/login.svelte?raw";
import appSource from "../../App.svelte?raw";
import generalSettingsSource from "../connectedGeneralSettingInputs.svelte?raw";
import headerSource from "../headerrightnav.svelte?raw";
import globalHeaderSource from "../globalheader.svelte?raw";
import settingsSource from "../../routes/settings/settings.svelte?raw";
import certificateLinkSource from "../downloadCertificateLink.svelte?raw";

Expand Down Expand Up @@ -55,3 +56,14 @@ test("authenticated administrator identity is displayed from the verified sessio
expect(settingsSource).toContain("value={$store.api.username}");
expect(settingsSource).not.toContain('keyName="admin_username"');
});

test("login keeps clear and submit actions in one row", () => {
expect(loginSource).toContain("<ButtonSet>");
expect(loginSource).not.toContain("<ButtonSet stacked>");
});

test("logout signals the shell so the login route renders immediately", () => {
expect(headerSource).toContain('dispatch("loggedout")');
expect(globalHeaderSource).toContain('on:loggedout={() => dispatch("loggedout")}');
expect(appSource).toContain('on:loggedout={() => (state = "login")}');
});
6 changes: 6 additions & 0 deletions ui/src/components/__tests__/shell_foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import appSource from "../../App.svelte?raw";
import menuSource from "../../menu.ts?raw";
import mainSource from "../../main.ts?raw";
import logsSource from "../../routes/logs/logs.svelte?raw";
import servicesSource from "../../routes/services/services.svelte?raw";

const compact = (source: string) => source.replace(/\s+/g, " ");

Expand Down Expand Up @@ -54,3 +55,8 @@ test("Raspberry Pi storage guidance is not shown on the decision log", () => {
expect(logsSource).not.toContain("Raspberry Pi");
expect(logsSource).not.toContain("/tmp/log.db");
});

test("services page uses the standard page width like other routes", () => {
expect(servicesSource).toContain("<PageShell");
expect(servicesSource).not.toContain("narrow");
});
6 changes: 1 addition & 5 deletions ui/src/components/dnsArecords.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,7 @@
state="empty"
title={$_("No custom records")}
message={$_("Add a record when a local domain should resolve to a specific IPv4 address.")}
>
<Button size="small" icon={AddAlt} on:click={openCreate}>
{$_("Add record")}
</Button>
</ResourceState>
/>
{:else}
<div class="table-region">
<DataTable sortable size="compact" {headers} rows={data}>
Expand Down
9 changes: 7 additions & 2 deletions ui/src/components/globalheader.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { Header, SkipToContent } from "carbon-components-svelte";
import { onMount } from "svelte";
import { onMount, createEventDispatcher } from "svelte";
import { store } from "../store/apistore";
import { routeHref } from "../menu";
import Headermenu from "./headermenu.svelte";
Expand All @@ -11,6 +11,8 @@
export let pathname = "/";
let version = "";

const dispatch = createEventDispatcher<{ loggedout: void }>();

onMount(async () => {
try {
const data = await $store.api.doCall("/about");
Expand All @@ -32,5 +34,8 @@
<SkipToContent />
</svelte:fragment>
<Headermenu {pathname} />
<Headerrightnav bind:userProfilePanelOpen />
<Headerrightnav
bind:userProfilePanelOpen
on:loggedout={() => dispatch("loggedout")}
/>
</Header>
4 changes: 4 additions & 0 deletions ui/src/components/headerrightnav.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
} from "carbon-components-svelte";
import { UserAvatarFilledAlt } from "carbon-icons-svelte";
import { _ } from "svelte-i18n";
import { createEventDispatcher } from "svelte";
import { store } from "../store/apistore";
import { gsNavigate } from "../lib/navigate";
import ConnectedGeneralSettingInputs from "./connectedGeneralSettingInputs.svelte";

export let userProfilePanelOpen = false;

const dispatch = createEventDispatcher<{ loggedout: void }>();

let updatePassword: (() => Promise<void>) | undefined;
let modalOpen = false;

Expand All @@ -26,6 +29,7 @@
userProfilePanelOpen = false;
modalOpen = false;
gsNavigate("/login", { replace: true });
dispatch("loggedout");
};

const savePassword = () => {
Expand Down
2 changes: 1 addition & 1 deletion ui/src/routes/login/login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
bind:value={password}
invalidText={invalidMessage}
/>
<ButtonSet stacked>
<ButtonSet>
<Button
size="lg"
kind="secondary"
Expand Down
1 change: 0 additions & 1 deletion ui/src/routes/services/services.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<PageShell
title="Services"
description="Control the gateway services running on this installation."
narrow
>
<svelte:fragment slot="breadcrumb">
<Breadcrumb noTrailingSlash>
Expand Down
Loading