mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
feat(helm): helm actions [r8s-259] (#715)
Co-authored-by: James Player <james.player@portainer.io> Co-authored-by: Cara Ryan <cara.ryan@portainer.io> Co-authored-by: stevensbkang <skan070@gmail.com>
This commit is contained in:
parent
dfa32b6755
commit
4ee349bd6b
117 changed files with 4161 additions and 696 deletions
|
@ -1,32 +1,184 @@
|
|||
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';
|
||||
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 <Input /> for more details)
|
||||
const [selectedCompareRevisionNumber, setSelectedCompareRevisionNumber] =
|
||||
useState(NaN);
|
||||
const [diffViewMode, setDiffViewMode] = useState<DiffViewMode>('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 (
|
||||
<NavTabs<Tab>
|
||||
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
|
||||
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<Tab>[] {
|
||||
// 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: <ResourcesTable />,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
Events
|
||||
{eventWarningCount >= 1 && (
|
||||
<Badge type="warnSecondary">
|
||||
<Icon icon={AlertTriangle} className="!mr-1" />
|
||||
{eventWarningCount}
|
||||
</Badge>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
id: 'events',
|
||||
children: (
|
||||
<HelmEventsDatatable
|
||||
namespace={release.namespace ?? ''}
|
||||
releaseResources={release.info?.resources ?? []}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: 'Values',
|
||||
id: 'values',
|
||||
|
@ -34,35 +186,97 @@ function helmTabs(
|
|||
<ValuesDetails
|
||||
values={release.values}
|
||||
isUserSupplied={isUserSupplied}
|
||||
setIsUserSupplied={setIsUserSupplied}
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
compareValues={compareRelease?.values}
|
||||
compareRevisionNumberFetched={compareRelease?.version}
|
||||
isCompareReleaseLoading={isCompareReleaseLoading}
|
||||
isCompareReleaseError={isCompareReleaseError}
|
||||
diffControl={
|
||||
<DiffControl
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
latestRevisionNumber={latestRevisionNumber}
|
||||
earliestRevisionNumber={earliestRevisionNumber}
|
||||
compareRevisionNumber={compareRevisionNumber}
|
||||
setCompareRevisionNumber={setCompareRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
setDiffViewMode={setDiffViewMode}
|
||||
isUserSupplied={isUserSupplied}
|
||||
setIsUserSupplied={setIsUserSupplied}
|
||||
showUserSuppliedCheckbox
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: 'Manifest',
|
||||
id: 'manifest',
|
||||
children: <ManifestDetails manifest={release.manifest} />,
|
||||
children: (
|
||||
<ManifestDetails
|
||||
manifest={release.manifest}
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
compareManifest={compareRelease?.manifest}
|
||||
compareRevisionNumberFetched={compareRelease?.version}
|
||||
isCompareReleaseLoading={isCompareReleaseLoading}
|
||||
isCompareReleaseError={isCompareReleaseError}
|
||||
diffControl={
|
||||
showDiffControl && (
|
||||
<DiffControl
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
latestRevisionNumber={latestRevisionNumber}
|
||||
earliestRevisionNumber={earliestRevisionNumber}
|
||||
compareRevisionNumber={compareRevisionNumber}
|
||||
setCompareRevisionNumber={setCompareRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
setDiffViewMode={setDiffViewMode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
),
|
||||
},
|
||||
!!release.info?.notes && {
|
||||
label: 'Notes',
|
||||
id: 'notes',
|
||||
children: <NotesDetails notes={release.info.notes} />,
|
||||
children: (
|
||||
<NotesDetails
|
||||
notes={release.info.notes}
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
compareNotes={compareRelease?.info?.notes}
|
||||
compareRevisionNumberFetched={compareRelease?.version}
|
||||
isCompareReleaseLoading={isCompareReleaseLoading}
|
||||
isCompareReleaseError={isCompareReleaseError}
|
||||
diffControl={
|
||||
showDiffControl && (
|
||||
<DiffControl
|
||||
selectedRevisionNumber={selectedRevisionNumber}
|
||||
latestRevisionNumber={latestRevisionNumber}
|
||||
earliestRevisionNumber={earliestRevisionNumber}
|
||||
compareRevisionNumber={compareRevisionNumber}
|
||||
setCompareRevisionNumber={setCompareRevisionNumber}
|
||||
diffViewMode={diffViewMode}
|
||||
setDiffViewMode={setDiffViewMode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
export function ReleaseTabs({ release }: Props) {
|
||||
const [tab, setTab] = useState<Tab>('resources');
|
||||
// state is here so that the state isn't lost when the tab changes
|
||||
const [isUserSupplied, setIsUserSupplied] = useState(true);
|
||||
|
||||
return (
|
||||
<NavTabs<Tab>
|
||||
onSelect={setTab}
|
||||
selectedId={tab}
|
||||
type="pills"
|
||||
justified
|
||||
options={helmTabs(release, isUserSupplied, setIsUserSupplied)}
|
||||
/>
|
||||
);
|
||||
function parseValidTab(tab: string, hasNotes: boolean): Tab {
|
||||
if (
|
||||
tab === 'values' ||
|
||||
(tab === 'notes' && hasNotes) ||
|
||||
tab === 'manifest' ||
|
||||
tab === 'resources' ||
|
||||
tab === 'events'
|
||||
) {
|
||||
return tab;
|
||||
}
|
||||
return 'resources';
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue