From badd15fe4f9211c5c12bf13a6a97b74af04dab71 Mon Sep 17 00:00:00 2001 From: Gabriel Bernal Date: Thu, 18 Dec 2025 13:36:06 +0100 Subject: [PATCH 1/4] fix: request namespaced resources for filter options Signed-off-by: Gabriel Bernal --- web/src/attribute-filters.tsx | 46 +++++++++++++++++-- .../filters/attribute-value-data.tsx | 8 ++-- web/src/components/filters/filter.types.ts | 2 +- web/src/components/filters/search-select.tsx | 2 +- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/web/src/attribute-filters.tsx b/web/src/attribute-filters.tsx index a22985f38..bcde69915 100644 --- a/web/src/attribute-filters.tsx +++ b/web/src/attribute-filters.tsx @@ -142,12 +142,14 @@ const resourceDataSource = const { request, abort } = cancellableFetch(endpoint); - const abortFunction = resourceAbort[resource]; + const abortKey = namespace ? `${resource}-${namespace}` : resource; + + const abortFunction = resourceAbort[abortKey]; if (abortFunction) { abortFunction(); } - resourceAbort[resource] = abort; + resourceAbort[abortKey] = abort; const response = await request(); @@ -295,14 +297,22 @@ export const availableAttributes = ({ name: 'Pods', label: podLabel, id: 'pod', - options: getPodAttributeOptions(tenant, config, schema), + options: (filters) => { + const selectedNamespaces = filters?.namespace ? Array.from(filters.namespace) : undefined; + + return getPodAttributeOptions(tenant, config, schema, selectedNamespaces)(); + }, valueType: 'checkbox-select', }, { name: 'Containers', label: containerLabel, id: 'container', - options: getContainerAttributeOptions(tenant, config, schema), + options: (filters) => { + const selectedNamespaces = filters?.namespace ? Array.from(filters.namespace) : undefined; + + return getContainerAttributeOptions(tenant, config, schema, selectedNamespaces)(); + }, expandSelection: (selections) => { const podSelections = new Set(); const containerSelections = new Set(); @@ -775,9 +785,17 @@ const getPodAttributeOptions = ( tenant: string, config: Config, schema: Schema, + namespaces?: Array, ): (() => Promise) => { const { podLabel } = getAttributeLabels(schema); + const namespacedPodsResources: Array> = []; + + // get pods in selected namespaces for users that have restricted access + for (const ns of namespaces || []) { + namespacedPodsResources.push(resourceDataSource({ resource: 'pods', namespace: ns })()); + } + return () => Promise.allSettled>([ lokiLabelValuesDataSource({ @@ -786,6 +804,7 @@ const getPodAttributeOptions = ( labelName: podLabel, })(), resourceDataSource({ resource: 'pods' })(), + ...namespacedPodsResources, ]).then((results) => { const podOptions: Set = new Set(); results.forEach((result) => { @@ -803,11 +822,29 @@ const getContainerAttributeOptions = ( tenant: string, config: Config, schema: Schema, + namespaces?: Array, ): (() => Promise) => { const { containerLabel, podLabel } = getAttributeLabels(schema); const seriesQuery = `{ ${containerLabel}!="", ${podLabel}!="" }`; + const namespacedPodsResources: Array> = []; + + // get containers in selected namespaces for users that have restricted access + for (const ns of namespaces || []) { + namespacedPodsResources.push( + resourceDataSource({ + resource: 'pods', + namespace: ns, + mapper: (resource) => + resource?.spec?.containers.map((container) => ({ + option: `${resource?.metadata?.name} / ${container.name}`, + value: `${resource?.metadata?.name} / ${container.name}`, + })) ?? [], + })(), + ); + } + return () => Promise.allSettled>([ lokiSeriesDataSource({ @@ -837,6 +874,7 @@ const getContainerAttributeOptions = ( value: `${resource?.metadata?.name} / ${container.name}`, })) ?? [], })(), + ...namespacedPodsResources, ]).then((results) => { const uniqueContainers = new Set(); results.forEach((result) => { diff --git a/web/src/components/filters/attribute-value-data.tsx b/web/src/components/filters/attribute-value-data.tsx index 097f7c706..c1794f44a 100644 --- a/web/src/components/filters/attribute-value-data.tsx +++ b/web/src/components/filters/attribute-value-data.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import { Attribute, Option } from './filter.types'; +import { Attribute, Filters, Option } from './filter.types'; import { useBoolean } from '../../hooks/useBoolean'; type UseAttributeValueDataHookResult = { - getAttributeOptions: (searchQuery?: string) => void; + getAttributeOptions: (filters?: Filters) => void; attributeOptions: Array