1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 05:45:22 +02:00

feat(helm): enhance helm chart install [r8s-341] (#766)

This commit is contained in:
Ali 2025-06-05 13:13:45 +12:00 committed by GitHub
parent caac45b834
commit a9061e5258
29 changed files with 864 additions and 562 deletions

View file

@ -0,0 +1,34 @@
import { useQuery } from '@tanstack/react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { withGlobalError } from '@/react-tools/react-query';
type Params = {
chart: string;
repo: string;
version?: string;
};
async function getHelmChartValues(params: Params) {
try {
const response = await axios.get<string>(`/templates/helm/values`, {
params,
});
return response.data;
} catch (err) {
throw parseAxiosError(err as Error, 'Unable to get Helm chart values');
}
}
export function useHelmChartValues(params: Params) {
return useQuery({
queryKey: ['helm-chart-values', params.repo, params.chart, params.version],
queryFn: () => getHelmChartValues(params),
enabled: !!params.chart && !!params.repo,
select: (data) => ({
values: data,
}),
staleTime: 60 * 1000 * 20, // 60 minutes, because values are not expected to change often
...withGlobalError('Unable to get Helm chart values'),
});
}

View file

@ -0,0 +1,103 @@
import { useQuery, useQueries } from '@tanstack/react-query';
import { useMemo } from 'react';
import { compact, flatMap } from 'lodash';
import { withGlobalError } from '@/react-tools/react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { useCurrentUser } from '@/react/hooks/useUser';
import { getHelmRepositories } from './useHelmChartList';
interface HelmSearch {
entries: Entries;
}
interface Entries {
[key: string]: { version: string }[];
}
export interface ChartVersion {
Repo: string;
Version: string;
}
/**
* Hook to fetch all Helm repositories for the current user
*/
export function useHelmRepositories() {
const { user } = useCurrentUser();
return useQuery(
['helm', 'repositories'],
async () => getHelmRepositories(user.Id),
{
enabled: !!user.Id,
...withGlobalError('Unable to retrieve helm repositories'),
}
);
}
/**
* React hook to get a list of available versions for a chart from specified repositories
*
* @param chart The chart name to get versions for
* @param repositories Array of repository URLs to search in
*/
export function useHelmRepoVersions(
chart: string,
staleTime: number,
repositories: string[] = [],
useCache: boolean = true
) {
// Fetch versions from each repository in parallel as separate queries
const versionQueries = useQueries({
queries: useMemo(
() =>
repositories.map((repo) => ({
queryKey: ['helm', 'repositories', chart, repo, useCache],
queryFn: () => getSearchHelmRepo(repo, chart, useCache),
enabled: !!chart && repositories.length > 0,
staleTime,
...withGlobalError(`Unable to retrieve versions from ${repo}`),
})),
[repositories, chart, staleTime, useCache]
),
});
// Combine the results from all repositories for easier consumption
const allVersions = useMemo(() => {
const successfulResults = compact(versionQueries.map((q) => q.data));
return flatMap(successfulResults);
}, [versionQueries]);
return {
data: allVersions,
isInitialLoading: versionQueries.some((q) => q.isLoading),
isError: versionQueries.some((q) => q.isError),
isFetching: versionQueries.some((q) => q.isFetching),
refetch: () => Promise.all(versionQueries.map((q) => q.refetch())),
};
}
/**
* Get Helm repositories for user
*/
async function getSearchHelmRepo(
repo: string,
chart: string,
useCache: boolean = true
): Promise<ChartVersion[]> {
try {
const { data } = await axios.get<HelmSearch>(`templates/helm`, {
params: { repo, chart, useCache },
});
const versions = data.entries[chart];
return (
versions?.map((v) => ({
Repo: repo,
Version: v.version,
})) ?? []
);
} catch (err) {
throw parseAxiosError(err, 'Unable to retrieve helm repositories for user');
}
}

View file

@ -0,0 +1,36 @@
import { useQueryClient, useMutation } from '@tanstack/react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { withGlobalError, withInvalidate } from '@/react-tools/react-query';
import { queryKeys as applicationsQueryKeys } from '@/react/kubernetes/applications/queries/query-keys';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { HelmRelease, UpdateHelmReleasePayload } from '../types';
export function useUpdateHelmReleaseMutation(environmentId: EnvironmentId) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: UpdateHelmReleasePayload) =>
updateHelmRelease(environmentId, payload),
...withInvalidate(queryClient, [
[environmentId, 'helm', 'releases'],
applicationsQueryKeys.applications(environmentId),
]),
...withGlobalError('Unable to uninstall helm application'),
});
}
async function updateHelmRelease(
environmentId: EnvironmentId,
payload: UpdateHelmReleasePayload
) {
try {
const { data } = await axios.post<HelmRelease>(
`endpoints/${environmentId}/kubernetes/helm`,
payload
);
return data;
} catch (err) {
throw parseAxiosError(err, 'Unable to update helm release');
}
}