From 956943edbb95cefee9344ab9b165a99cdbc2bce7 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 16 May 2026 22:46:51 +0300 Subject: [PATCH] feat(proxies): per-row Triggers deep-link to /apps/[id]#bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proxies page now exposes the trigger bindings for each routed workload via a per-row action chip. Resolves the explicit "what's next" call-out in WORKLOAD_REFACTOR_TODO under Priority 3 polish. - Added id="bindings" to the existing trigger bindings
on /apps/[id]/+page.svelte so URL fragments resolve to the panel. - New triggersHref(route) helper in /proxies that builds /apps/{workload_id}#bindings; code-pointer comment explains the back-compat naming (ProxyRoute.project_id is actually the workload ID — see internal/store/models.go:110-113), so a future contributor doesn't trip on the mismatch and rip the helper out. - New right-aligned "Actions" column with a button-shaped link; defensive — falls back to — when project_id is absent. - Three new i18n keys under proxies.* (actions, viewTriggers, viewTriggersTitle) mirrored across EN + RU. Key parity now 1512 each. No backend change needed; ListProxyRoutes already selects w.id into ProxyRoute.project_id. Workload-aware batch endpoints (showing trigger counts inline) were deliberately out of scope for this half-turn — flagged as a future enhancement only if users want inline counts. Verification: svelte-check 0 errors + 3 pre-existing warnings in TagCombobox; go build + go test ./... all green across 20 packages. --- web/src/lib/i18n/en.json | 5 ++++- web/src/lib/i18n/ru.json | 5 ++++- web/src/routes/apps/[id]/+page.svelte | 2 +- web/src/routes/proxies/+page.svelte | 22 ++++++++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/web/src/lib/i18n/en.json b/web/src/lib/i18n/en.json index 595bac3..696a4a9 100644 --- a/web/src/lib/i18n/en.json +++ b/web/src/lib/i18n/en.json @@ -392,7 +392,10 @@ "noMatch": "No routes match your search.", "loadFailed": "Failed to load proxy routes", "route": "route", - "routes": "routes" + "routes": "routes", + "actions": "Actions", + "viewTriggers": "Triggers", + "viewTriggersTitle": "View trigger bindings for this workload" }, "common": { "cancel": "Cancel", diff --git a/web/src/lib/i18n/ru.json b/web/src/lib/i18n/ru.json index 89c0ab8..93772d6 100644 --- a/web/src/lib/i18n/ru.json +++ b/web/src/lib/i18n/ru.json @@ -392,7 +392,10 @@ "noMatch": "Нет маршрутов, соответствующих поиску.", "loadFailed": "Не удалось загрузить прокси-маршруты", "route": "маршрут", - "routes": "маршрутов" + "routes": "маршрутов", + "actions": "Действия", + "viewTriggers": "Триггеры", + "viewTriggersTitle": "Посмотреть привязки триггеров для этой нагрузки" }, "common": { "cancel": "Отмена", diff --git a/web/src/routes/apps/[id]/+page.svelte b/web/src/routes/apps/[id]/+page.svelte index 52a3a06..d0c28fe 100644 --- a/web/src/routes/apps/[id]/+page.svelte +++ b/web/src/routes/apps/[id]/+page.svelte @@ -2168,7 +2168,7 @@ "Add trigger" opens a modal with two tabs: inline-create a new trigger record, or pick an existing one. --> {#if !editing} -
+

diff --git a/web/src/routes/proxies/+page.svelte b/web/src/routes/proxies/+page.svelte index e6d7829..2f9cd22 100644 --- a/web/src/routes/proxies/+page.svelte +++ b/web/src/routes/proxies/+page.svelte @@ -57,6 +57,14 @@ return q ? `/containers?q=${q}` : '/containers'; } + // `project_id` on a ProxyRoute is actually the workload ID + // (back-compat naming — see internal/store/models.go:110-113). Anchor + // at the bindings section on /apps/[id] so the operator lands directly + // on the trigger list for this workload. + function triggersHref(route: ProxyRoute): string { + return route.project_id ? `/apps/${route.project_id}#bindings` : '/triggers'; + } + async function loadRoutes() { loading = true; try { @@ -136,6 +144,7 @@ {$t('proxies.tag')} {$t('proxies.port')} {$t('proxies.status')} + {$t('proxies.actions')} @@ -172,6 +181,19 @@ + + {#if route.project_id} + + {$t('proxies.viewTriggers')} + + {:else} + + {/if} + {/each}