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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG

## v2.4.0 (25 September 2026)

### Administration UI

- Redesigned the sign-in page around the Carbon authentication pattern: a light G10 surface with a branded GateSentry header, extra-large labeled inputs, and one Clear / Sign in action row
- The inspection certificate download is now a de-emphasized ghost action inside the sign-in card instead of a standalone tertiary button, with the same download available in Settings
- Setup, session-checking, and unavailable screens share the same refreshed authentication layout

## v2.3.1 (25 September 2026)

### Fixes
Expand Down
98 changes: 49 additions & 49 deletions application/webserver/frontend/files/fs/bundle.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion application/webserver/frontend/files/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Gatesentry</title>
<script type="module" crossorigin src="/fs/bundle.js"></script>
<link rel="stylesheet" href="/fs/style-6dc8a68e.css">
<link rel="stylesheet" href="/fs/style-5c38955c.css">
</head>
<body>
<div id="app"></div>
Expand Down
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.1"
var GATESENTRY_VERSION = "2.4.0"
var GS_BOUND_ADDRESS = ":"
var R *application.GSRuntime

Expand Down
41 changes: 31 additions & 10 deletions ui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -191,21 +191,36 @@ textarea {
align-items: center;
justify-content: center;
gap: 1.5rem;
background:
linear-gradient(135deg, rgba(15, 98, 254, 0.12), transparent 44%),
#161616;
background: #f4f4f4;
}

.auth-shell__card {
width: min(100%, 32rem);
width: min(100%, 28rem);
padding: clamp(1.5rem, 5vw, 2.5rem);
background: #ffffff;
box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.28);
border: 1px solid #e0e0e0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.auth-shell__brand {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 2.5rem;
color: #0f62fe;
}

.auth-shell__mark {
display: inline-flex;
width: 1.5rem;
height: 1.5rem;
align-items: center;
justify-content: center;
background: #0f62fe;
color: #ffffff;
}

.auth-shell__name {
color: #161616;
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.08em;
Expand All @@ -217,7 +232,7 @@ textarea {
}

.auth-shell__header h1 {
font-size: clamp(2rem, 7vw, 2.625rem);
font-size: clamp(1.75rem, 5vw, 2.25rem);
font-weight: 300;
line-height: 1.15;
}
Expand All @@ -239,14 +254,20 @@ textarea {
margin-top: 1.5rem;
}

.auth-shell__card .bx--btn-set .bx--btn {
min-width: 0;
flex-shrink: 1;
}

.auth-shell__footer {
width: min(100%, 32rem);
color: #f4f4f4;
width: min(100%, 28rem);
color: #525252;
font-size: 0.875rem;
text-align: center;
}

.auth-shell__footer a {
color: #78a9ff;
color: #0f62fe;
}

.notification-region {
Expand Down
11 changes: 11 additions & 0 deletions ui/src/components/__tests__/secure_setup_ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ test("login keeps clear and submit actions in one row", () => {
expect(loginSource).not.toContain("<ButtonSet stacked>");
});

test("login follows the Carbon auth form composition", () => {
expect(loginSource).not.toContain("FluidForm");
expect(loginSource).toContain("<Form on:submit={handleLogin}>");
expect(loginSource).toContain('size="xl"');
expect(loginSource).toContain('autocomplete="username"');
expect(loginSource).toContain('autocomplete="current-password"');
// The certificate download is a de-emphasized secondary action inside the card.
expect(loginSource).toContain('<DownloadCertificateLink kind="ghost" />');
expect(loginSource).not.toContain('slot="footer"');
});

test("logout signals the shell so the login route renders immediately", () => {
expect(headerSource).toContain('dispatch("loggedout")');
expect(globalHeaderSource).toContain('on:loggedout={() => dispatch("loggedout")}');
Expand Down
5 changes: 4 additions & 1 deletion ui/src/components/downloadCertificateLink.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import { _ } from "svelte-i18n";
import { getBasePath } from "../lib/navigate";

export let kind: "primary" | "secondary" | "tertiary" | "ghost" = "tertiary";
export let size: "default" | "field" | "small" | "lg" | "xl" = "small";

const link = getBasePath() + "/api/files/certificate";
</script>

<Button href={link} icon={Download} kind="tertiary" size="small" download>
<Button href={link} icon={Download} {kind} {size} download>
{$_("Download certificate")}
</Button>
9 changes: 8 additions & 1 deletion ui/src/components/layout/AuthShell.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
<script lang="ts">
import { Security } from "carbon-icons-svelte";

export let title = "";
export let description = "";
</script>

<main class="auth-shell">
<section class="auth-shell__card" aria-labelledby="auth-shell-title">
<div class="auth-shell__brand">GateSentry</div>
<div class="auth-shell__brand">
<span class="auth-shell__mark" aria-hidden="true">
<Security size={16} />
</span>
<span class="auth-shell__name">GateSentry</span>
</div>
<header class="auth-shell__header">
<h1 id="auth-shell-title">{title}</h1>
{#if description}<p>{description}</p>{/if}
Expand Down
41 changes: 19 additions & 22 deletions ui/src/routes/login/login.svelte
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
<script lang="ts">
import {
Button,
ButtonSet,
FluidForm,
PasswordInput,
TextInput,
} from "carbon-components-svelte";
import { ChevronRight, Close } from "carbon-icons-svelte";
import { Button, ButtonSet, Form, PasswordInput, TextInput } from "carbon-components-svelte";
import { store } from "../../store/apistore";
import { gsNavigate } from "../../lib/navigate";
import { notificationstore } from "../../store/notifications";
import { createNotificationError } from "../../lib/utils";
import { _ } from "svelte-i18n";
import { createEventDispatcher } from "svelte";
import DownloadCertificateLink from "../../components/downloadCertificateLink.svelte";
import AuthShell from "../../components/layout/AuthShell.svelte";
import DownloadCertificateLink from "../../components/downloadCertificateLink.svelte";

let username = "";
let password = "";
Expand Down Expand Up @@ -71,8 +64,9 @@
title={$_("Sign in")}
description={$_("Manage protection, policies, and connected devices.")}
>
<FluidForm on:submit={handleLogin}>
<Form on:submit={handleLogin}>
<TextInput
size="xl"
{invalid}
autocomplete="username"
labelText={$_("User name")}
Expand All @@ -82,37 +76,40 @@
invalidText={invalidMessage}
/>
<PasswordInput
size="xl"
{invalid}
autocomplete="current-password"
required
labelText={$_("Password")}
placeholder={$_("Enter password")}
tooltipAlignment="end"
bind:value={password}
invalidText={invalidMessage}
/>
<ButtonSet>
<Button
size="lg"
kind="secondary"
icon={Close}
type="button"
disabled={submitting || (!username && !password)}
on:click={cancel}
>
{$_("Clear")}
</Button>
<Button
size="lg"
type="submit"
icon={ChevronRight}
disabled={submitting || !username || !password}
>
<Button type="submit" disabled={submitting || !username || !password}>
{submitting ? $_("Signing in…") : $_("Sign in")}
</Button>
</ButtonSet>
</FluidForm>
</Form>

<svelte:fragment slot="footer">
<DownloadCertificateLink />
</svelte:fragment>
<div class="login-secondary">
<DownloadCertificateLink kind="ghost" />
</div>
</AuthShell>

<style>
.login-secondary {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #e0e0e0;
}
</style>
Loading