Skip to content

Commit 3cd4103

Browse files
Merge pull request #36 from InstaNode-dev/slice-1-env-filter-2026-05-12
dashboard: env switcher actually filters resources + deployments (slice 1)
2 parents 383e0f7 + 79972d8 commit 3cd4103

4 files changed

Lines changed: 18 additions & 20 deletions

File tree

src/api/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,10 @@ function adaptResource(r: any): Resource {
284284
}
285285
}
286286

287-
export async function listResources(): Promise<{ ok: true; items: Resource[]; total: number }> {
288-
const r = await call<ResourceListResp>('/api/v1/resources')
287+
export async function listResources(env?: string): Promise<{ ok: true; items: Resource[]; total: number }> {
288+
// ?env= filters server-side. Omit for all envs (the legacy behavior).
289+
const path = env ? `/api/v1/resources?env=${encodeURIComponent(env)}` : '/api/v1/resources'
290+
const r = await call<ResourceListResp>(path)
289291
const items = (r.items ?? []).map(adaptResource)
290292
return { ok: true, items, total: r.total ?? items.length }
291293
}
@@ -458,11 +460,13 @@ function adaptDeployment(d: DeploymentRespItem): DashboardDeployment {
458460
}
459461
}
460462

461-
export async function listDeployments(): Promise<{ ok: true; items: DashboardDeployment[]; total: number }> {
463+
export async function listDeployments(env?: string): Promise<{ ok: true; items: DashboardDeployment[]; total: number }> {
462464
// No try/catch fallback to empty — errors propagate so DeploymentsPage
463465
// can render a real error state instead of silently lying. The list
464466
// endpoint requires auth; 401 still triggers the AuthGate redirect.
465-
const r = await call<DeploymentsListResp>('/api/v1/deployments')
467+
// ?env= filters server-side; omitting returns all envs (legacy behavior).
468+
const path = env ? `/api/v1/deployments?env=${encodeURIComponent(env)}` : '/api/v1/deployments'
469+
const r = await call<DeploymentsListResp>(path)
466470
const items = (r.items ?? []).map(adaptDeployment)
467471
return { ok: true, items, total: r.total ?? items.length }
468472
}

src/pages/DeploymentsPage.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@ import {
55
} from '../components/Common'
66
import * as api from '../api'
77
import type { DashboardDeployment } from '../api'
8+
import { useDashboardCtx } from '../hooks/useDashboardCtx'
89

910
export function DeploymentsPage() {
11+
const ctx = useDashboardCtx()
1012
const [items, setItems] = useState<DashboardDeployment[]>([])
1113
const [loading, setLoading] = useState(true)
1214

1315
// Source of truth: GET /api/v1/deployments (single-container apps via
14-
// POST /deploy/new). This replaces the previous listStacks() call,
15-
// which only returned multi-service stacks and therefore showed an
16-
// empty list for any team that had only ever used /deploy/new — even
17-
// when they had a live deployment. We keep falling back to listStacks
18-
// implicitly on DeployDetailPage so legacy stack-mode deploys still
19-
// open, but the primary surface is the deployments list.
16+
// POST /deploy/new). The env switcher in the sidebar drives the ?env=
17+
// query param; switching envs triggers a refetch via the dep array.
2018
useEffect(() => {
2119
let cancelled = false
2220
api
23-
.listDeployments()
21+
.listDeployments(ctx.env)
2422
.then((r) => {
2523
if (cancelled) return
2624
setItems(r.items)
@@ -37,7 +35,7 @@ export function DeploymentsPage() {
3735
return () => {
3836
cancelled = true
3937
}
40-
}, [])
38+
}, [ctx.env])
4139

4240
return (
4341
<>

src/pages/OverviewPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function OverviewPage() {
7575

7676
useEffect(() => {
7777
let alive = true
78-
Promise.all([api.listResources(), api.fetchActivity()]).then(([r, a]) => {
78+
Promise.all([api.listResources(ctx.env), api.fetchActivity()]).then(([r, a]) => {
7979
if (!alive) return
8080
setResources(r.items)
8181
setActivity(a.items)
@@ -84,7 +84,7 @@ export function OverviewPage() {
8484
return () => {
8585
alive = false
8686
}
87-
}, [])
87+
}, [ctx.env])
8888

8989
// computed stats — no /overview endpoint exists, derived client-side
9090
const totalStorageMB = Math.round(resources.reduce((s, r) => s + r.storage_bytes, 0) / 1_000_000)

src/pages/ResourcesPage.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import { useDashboardCtx } from '../hooks/useDashboardCtx'
1111
const TYPES: (ResourceType | 'all')[] = ['all', 'postgres', 'redis', 'mongodb', 'queue', 'storage', 'webhook']
1212

1313
export function ResourcesPage() {
14-
// We still read team tier from ctx for the prompt cards — env, however,
15-
// is intentionally NOT consumed here. The backend doesn't honor a multi-env
16-
// filter (no GET /api/v1/resources?env=…), so surfacing chips would be a lie.
17-
// Env stays scoped to VaultPage where it's genuinely backed by per-env rows.
1814
const ctx = useDashboardCtx()
1915
const [items, setItems] = useState<Resource[]>([])
2016
const [loading, setLoading] = useState(true)
@@ -28,7 +24,7 @@ export function ResourcesPage() {
2824
let alive = true
2925
setLoading(true)
3026
setErr(null)
31-
api.listResources()
27+
api.listResources(ctx.env)
3228
.then((r) => {
3329
if (!alive) return
3430
setItems(r.items)
@@ -40,7 +36,7 @@ export function ResourcesPage() {
4036
setLoading(false)
4137
})
4238
return () => { alive = false }
43-
}, [])
39+
}, [ctx.env])
4440

4541
const filtered = useMemo(
4642
() => items.filter((r) => type === 'all' || r.resource_type === type),

0 commit comments

Comments
 (0)