import { useState, useMemo } from 'react'; import { components, OptionProps } from 'react-select'; import { PortainerSelect, Option, } from '@/react/components/form-components/PortainerSelect'; import { Link } from '@/react/components/Link'; import { InsightsBox } from '@@/InsightsBox'; import { SearchBar } from '@@/datatables/SearchBar'; import { InlineLoader } from '@@/InlineLoader'; import { Chart } from '../types'; import { HelmTemplatesListItem } from './HelmTemplatesListItem'; interface Props { isLoading: boolean; charts?: Chart[]; selectAction: (chart: Chart) => void; registries: string[]; selectedRegistry: string | null; setSelectedRegistry: (registry: string | null) => void; } export function HelmTemplatesList({ isLoading, charts = [], selectAction, registries, selectedRegistry, setSelectedRegistry, }: Props) { const [textFilter, setTextFilter] = useState(''); const [selectedCategory, setSelectedCategory] = useState(null); const categories = useMemo(() => getCategories(charts), [charts]); const registryOptions = useMemo( () => registries.map((registry) => ({ label: registry, value: registry, })), [registries] ); const filteredCharts = useMemo( () => getFilteredCharts(charts, textFilter, selectedCategory), [charts, textFilter, selectedCategory] ); return (
Helm chart
setTextFilter(value)} placeholder="Search..." data-cy="helm-templates-search" className="!mr-0 h-9" />
Select the Helm chart to use. Bring further Helm charts into your selection list via{' '} User settings - Helm repositories .
At present Portainer does not support OCI format Helm charts. Support for OCI charts will be available in a future release.
If you would like to provide feedback on OCI support or get access to early releases to test this functionality,{' '} please get in touch . } />
{filteredCharts.map((chart) => ( ))} {filteredCharts.length === 0 && textFilter && (
No Helm charts found
)} {isLoading && (
Loading helm charts... {charts.length === 0 && (
Initial download of Helm charts can take a few minutes
)}
)} {!isLoading && charts.length === 0 && selectedRegistry && (
No helm charts available in this registry.
)} {!selectedRegistry && (
Please select a registry to view available Helm charts.
)}
); } // truncate the registry text, because some registry names are urls, which are too long function RegistryOption(props: OptionProps>) { const { data: registry } = props; return (
{/* eslint-disable-next-line react/jsx-props-no-spreading */} {registry.value}
); } /** * Get categories from charts * @param charts - The charts to get the categories from * @returns Categories */ function getCategories(charts: Chart[]) { const annotationCategories = charts .map((chart) => chart.annotations?.category) // get category .filter((c): c is string => !!c); // filter out nulls/undefined const availableCategories = [...new Set(annotationCategories)].sort(); // unique and sort // Create options array in the format expected by PortainerSelect return availableCategories.map((cat) => ({ label: cat, value: cat, })); } /** * Get filtered charts * @param charts - The charts to get the filtered charts from * @param textFilter - The text filter * @param selectedCategory - The selected category * @returns Filtered charts */ function getFilteredCharts( charts: Chart[], textFilter: string, selectedCategory: string | null ) { return charts.filter((chart) => { // Text filter if ( textFilter && !chart.name.toLowerCase().includes(textFilter.toLowerCase()) && !chart.description.toLowerCase().includes(textFilter.toLowerCase()) ) { return false; } // Category filter if ( selectedCategory && (!chart.annotations || chart.annotations.category !== selectedCategory) ) { return false; } return true; }); }