import { useState } from 'react'; import { compact } from 'lodash'; import { useCurrentStateAndParams, useRouter } from '@uirouter/react'; import { AlertTriangle } from 'lucide-react'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useEvents } from '@/react/kubernetes/queries/useEvents'; import { NavTabs, Option } from '@@/NavTabs'; import { Badge } from '@@/Badge'; import { Icon } from '@@/Icon'; import { HelmRelease } from '../../types'; import { useHelmHistory } from '../queries/useHelmHistory'; import { ManifestDetails } from './ManifestDetails'; import { NotesDetails } from './NotesDetails'; import { ValuesDetails } from './ValuesDetails'; import { ResourcesTable } from './ResourcesTable/ResourcesTable'; import { DiffControl, DiffViewMode } from './DiffControl'; import { useHelmReleaseToCompare } from './useHelmReleaseToCompare'; import { filterRelatedEvents, HelmEventsDatatable, useHelmEventsTableState, } from './HelmEventsDatatable'; type Props = { release: HelmRelease; selectedRevision: number; }; type Tab = 'values' | 'notes' | 'manifest' | 'resources' | 'events'; export function ReleaseTabs({ release, selectedRevision }: Props) { const { params: { tab }, } = useCurrentStateAndParams(); const router = useRouter(); const environmentId = useEnvironmentId(); // state is here so that the state isn't lost when the tab changes const [isUserSupplied, setIsUserSupplied] = useState(true); // start with NaN so that the input is empty (see for more details) const [selectedCompareRevisionNumber, setSelectedCompareRevisionNumber] = useState(NaN); const [diffViewMode, setDiffViewMode] = useState('view'); const historyQuery = useHelmHistory( environmentId, release.name, release.namespace ?? '' ); const earliestRevisionNumber = historyQuery.data?.[historyQuery.data.length - 1]?.version ?? release.version ?? 1; const latestRevisionNumber = historyQuery.data?.[0]?.version ?? release.version ?? 1; const { compareRelease, isCompareReleaseLoading, isCompareReleaseError } = useHelmReleaseToCompare( release, earliestRevisionNumber, latestRevisionNumber, diffViewMode, selectedRevision, selectedCompareRevisionNumber ); const { autoRefreshRate } = useHelmEventsTableState(); const { data: eventWarningCount } = useEvents(environmentId, { namespace: release.namespace ?? '', queryOptions: { autoRefreshRate: autoRefreshRate * 1000, select: (data) => { const relatedEvents = filterRelatedEvents( data, release.info?.resources ?? [] ); return relatedEvents.filter((e) => e.type === 'Warning').length; }, }, }); return ( onSelect={setTab} selectedId={parseValidTab(tab, !!release.info?.notes)} type="pills" justified options={helmTabs( release, isUserSupplied, setIsUserSupplied, earliestRevisionNumber, latestRevisionNumber, selectedRevision, selectedCompareRevisionNumber, setSelectedCompareRevisionNumber, diffViewMode, handleDiffViewChange, isCompareReleaseLoading, isCompareReleaseError, eventWarningCount ?? 0, compareRelease )} /> ); function handleDiffViewChange(diffViewMode: DiffViewMode) { setDiffViewMode(diffViewMode); if (latestRevisionNumber === earliestRevisionNumber) { return; } // if the input for compare revision number is NaN, set it to the previous revision number if ( Number.isNaN(selectedCompareRevisionNumber) && diffViewMode === 'specific' ) { if (selectedRevision > earliestRevisionNumber) { setSelectedCompareRevisionNumber(selectedRevision - 1); return; } // it could be useful to compare to the latest revision number if the selected revision number is the earliest revision number setSelectedCompareRevisionNumber(latestRevisionNumber); } } function setTab(tab: Tab) { router.stateService.go('kubernetes.helm', { tab, }); } } function helmTabs( release: HelmRelease, isUserSupplied: boolean, setIsUserSupplied: (isUserSupplied: boolean) => void, earliestRevisionNumber: number, latestRevisionNumber: number, selectedRevisionNumber: number, compareRevisionNumber: number, setCompareRevisionNumber: (compareRevisionNumber: number) => void, diffViewMode: DiffViewMode, setDiffViewMode: (diffViewMode: DiffViewMode) => void, isCompareReleaseLoading: boolean, isCompareReleaseError: boolean, eventWarningCount: number, compareRelease?: HelmRelease ): Option[] { // as long as the latest revision number is greater than the earliest revision number, there are changes to compare const showDiffControl = latestRevisionNumber > earliestRevisionNumber; return compact([ { label: 'Resources', id: 'resources', children: , }, { label: ( <> Events {eventWarningCount >= 1 && ( {eventWarningCount} )} ), id: 'events', children: ( ), }, { label: 'Values', id: 'values', children: ( } /> ), }, { label: 'Manifest', id: 'manifest', children: ( ) } /> ), }, !!release.info?.notes && { label: 'Notes', id: 'notes', children: ( ) } /> ), }, ]); } function parseValidTab(tab: string, hasNotes: boolean): Tab { if ( tab === 'values' || (tab === 'notes' && hasNotes) || tab === 'manifest' || tab === 'resources' || tab === 'events' ) { return tab; } return 'resources'; }