Skip to content

Add Frontend proxies tab to the HTTP routes page - #1258

Open
stephdl wants to merge 21 commits into
mainfrom
sdl-8098-frontend-proxies
Open

Add Frontend proxies tab to the HTTP routes page#1258
stephdl wants to merge 21 commits into
mainfrom
sdl-8098-frontend-proxies

Conversation

@stephdl

@stephdl stephdl commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Expose the Traefik trusted proxies settings in the cluster admin UI. Until now the only way to configure them was api-cli run module/traefik1/set-trusted-proxies.

The HTTP routes page gets a tab bar: the existing route table moves into a Routes tab, and a new Frontend proxies tab is added. The selected tab is kept in the view query parameter.

The new tab lists one row per node running behind a frontend HTTP proxy, with its proxy addresses and its trust depth, plus a text filter and a node filter. The Add/Edit modal takes the node, the proxy addresses (one per line) and the trust depth. The Add dropdown only offers nodes that are not configured yet, since set-trusted-proxies replaces the whole list of a node. Deleting a row sends an empty proxy list.

UI-only change: no Traefik action, schema or configuration template is touched.

Related issue

NethServer/dev#8098

@stephdl stephdl self-assigned this Jul 28, 2026
stephdl added a commit to NethServer/ns8-ui-lib that referenced this pull request Jul 30, 2026
Subpaths of the Carbon "network--3" icon, for empty states about network
configuration. NethServer/ns8-core#1258 needs it for the frontend proxies
table and carries a local copy in the meantime.
@stephdl
stephdl requested a review from AmaLuci August 3, 2026 10:20
@stephdl
stephdl force-pushed the sdl-8098-frontend-proxies branch 2 times, most recently from 45ae764 to 17d439b Compare August 6, 2026 13:06
@stephdl
stephdl requested review from andre8244 and removed request for AmaLuci August 6, 2026 13:07
stephdl added 4 commits August 6, 2026 17:08
Split HTTP routes page into tabs for routes and frontend proxies.
Recompute node list from clusterNodes instead of snapshotting once,
so it updates regardless of load order. Restart the read chain on
websocket reconnect and avoid duplicating routes from stale events.
@stephdl
stephdl force-pushed the sdl-8098-frontend-proxies branch from 17d439b to 24eaa01 Compare August 6, 2026 15:09
Comment thread core/ui/src/views/settings/SettingsHttpRoutes.vue Outdated
Comment thread core/ui/public/i18n/en/translation.json
Comment thread core/ui/public/i18n/en/translation.json Outdated
Comment thread core/ui/src/components/settings/ConfigureFrontendProxyModal.vue Outdated
@andre8244

Copy link
Copy Markdown
Contributor

is bad_ip_address i18n string used (maybe by the backend)? If not, we can remove it

@stephdl

stephdl commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Yes, by the backend. set-trusted-proxies returns error: bad_ip_address, and
setTrustedProxiesValidationFailed() resolves the key dynamically via
getI18nStringWithFallback() — same pattern as the other modals, so grep finds nothing.
Removing it would show the raw key on screen.

@stephdl
stephdl force-pushed the sdl-8098-frontend-proxies branch from 895f9ee to 7546cd1 Compare August 7, 2026 09:08
@stephdl
stephdl requested a review from andre8244 August 7, 2026 09:41
</template>
<template slot="secondary-button">{{ $t("common.cancel") }}</template>
<template slot="primary-button">{{
isEditing ? $t("common.save") : $t("common.add")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
isEditing ? $t("common.save") : $t("common.add")
isEditing ? $t("common.save") : $t("common.add_frontend_proxy")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The key lives in common now, and common.add is gone.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my suggestion was not accurate, add_frontend_proxy belongs to settings_http_routes section, not common

Comment thread core/ui/public/i18n/en/translation.json Outdated
"clear_search": "Clear search",
"settings": "Settings",
"cancel": "Cancel",
"add": "Add",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"add": "Add",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread core/ui/public/i18n/en/translation.json Outdated
Comment thread core/ui/public/i18n/en/translation.json Outdated
Comment thread core/ui/src/components/settings/ConfigureFrontendProxyModal.vue Outdated
Comment thread core/ui/public/i18n/en/translation.json Outdated
Comment thread core/ui/src/views/settings/SettingsHttpRoutes.vue
Comment thread core/ui/src/components/settings/HttpFrontendProxiesPanel.vue
Both route and frontend proxy modals declared their own IPv4 and IPv6
patterns. Move them to a shared mixin exposing isIpAddress (no prefix,
matching what set-trusted-proxies accepts) and isIpAddressOrCidr.

The route allow list now rejects leading-zero octets such as
192.168.001.1, which Python ipaddress refuses since 3.9.5.
Name the modal primary button after the action instead of a bare "Add",
reuse common.eg_value for the address placeholder, shorten the trust
depth error and tell the user the page reloads on its own.
The component is the body of a tab, and the routes tab gets a sibling
panel next.
Match the mockup and the frontend proxies tab: put the search box, the
node combo and a clear filters link on one row, drop the search box the
data table owned, and make the create button primary. Filtering to
nothing now shows a no results state instead of an empty table.

The node filter notification above the tabs is gone, the clear filters
link replaces it.

Move the tab body and its three modals to HttpRoutesPanel, mirroring
HttpFrontendProxiesPanel. The view keeps the query params, the tab
selector and the single list-installed-modules chain that feeds both
panels; each panel reloads from a traefikInstances watcher.

The node filter stays a query param, so the panel takes it as a prop and
mirrors it locally: repainting the combo box needs a synchronous write
that a round trip through the URL cannot guarantee.
@stephdl

stephdl commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Pushed. Four commits.

Also reworked the routes tab to match the mockup and the frontend proxies tab: search box, node combo and a clear filters link on one row, no search box inside the data table, primary create button. Filtering to nothing shows a no results state. The node filter notification above the tabs is gone, the clear filters link replaces it.

Two things worth a look:

  • The route allow list now rejects leading-zero octets such as 192.168.001.1. Side effect of sharing one strict IPv4 pattern. Traefik would reject them anyway.
  • The ns8-ui-lib bump to 2.0.1 carries the Vue 2.7 major. core/ui is already on vue: ^2.7.0, so nothing breaks.

Verified against a cluster with the dev server: both tabs, filters, query params after reload, tab switching, IP validation, CIDR still accepted in the route allow list.

deleteRoute and setTrustedProxies registered raw $root.$once handlers
that nothing ever removed. Navigating away with a delete in flight ran
deleteRouteCompleted on a destroyed component and reissued the whole
list-routes batch, and the modal leaked four handlers per save because
only one of validation-failed and completed ever fires.

Track them like the read chain does and clear them on destroy.
clearListeners cannot stop a batch already suspended on an await: it
resumes, registers listeners for its remaining instances and decrements
the counter of the newer batch, which clears the skeleton rows early.

Give each batch a generation and bail out when it is no longer current.
The proxies panel had no instancesError watcher: a get-trusted-proxies
batch in flight when list-installed-modules failed left the table in
skeleton state for good. The routes panel already guards this.

created() and the isWebsocketConnected watcher both started a read, so a
cold page load created two list-installed-modules tasks and threw the
first result away.
@stephdl
stephdl requested a review from andre8244 August 25, 2026 12:10
cv-combo-box auto-filter narrows the option list as the user types, which
hides the sentinel and the other nodes while a value is being edited.
Mirror the routes tab: the view owns the node filter as a query param, so
the selection survives a reload and can be linked to. The proxies table
gets its own param, the two tabs filter independently.
The label is specific to the HTTP routes page, common holds the strings
shared across pages.
Both HTTP routes tabs now match the TLS certificates layout: the primary
button sits on top of the search and filter bar.

@andre8244 andre8244 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's fix a i18n string then LGTM

"trust_depth_tooltip": "With a trust depth of 1, the client IP address is read from the last entry of the X-Forwarded-For header.",
"trust_depth_invalid": "Enter a number of 1 or higher",
"bad_ip_address": "Invalid IP address. Enter one IPv4 or IPv6 address per line, without CIDR prefix",
"frontend_proxy_restart_message": "HTTP clients connected to {node} will be briefly disconnected. The page should reload automatically — otherwise, reload it manually."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's fix this like in PR 1257

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants