diff --git a/api/http/handler/helm/helm_repo_search.go b/api/http/handler/helm/helm_repo_search.go
index 976558b9b..aab9c523d 100644
--- a/api/http/handler/helm/helm_repo_search.go
+++ b/api/http/handler/helm/helm_repo_search.go
@@ -7,7 +7,6 @@ import (
"github.com/portainer/portainer/pkg/libhelm/options"
httperror "github.com/portainer/portainer/pkg/libhttp/error"
- "github.com/portainer/portainer/pkg/libhttp/request"
"github.com/pkg/errors"
)
@@ -33,18 +32,13 @@ func (handler *Handler) helmRepoSearch(w http.ResponseWriter, r *http.Request) *
return httperror.BadRequest("Bad request", errors.New("missing `repo` query parameter"))
}
- chart, _ := request.RetrieveQueryParameter(r, "chart", false)
- useCache, _ := request.RetrieveBooleanQueryParameter(r, "useCache", false)
-
_, err := url.ParseRequestURI(repo)
if err != nil {
return httperror.BadRequest("Bad request", errors.Wrap(err, fmt.Sprintf("provided URL %q is not valid", repo)))
}
searchOpts := options.SearchRepoOptions{
- Repo: repo,
- Chart: chart,
- UseCache: useCache,
+ Repo: repo,
}
result, err := handler.helmPackageManager.SearchRepo(searchOpts)
diff --git a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.test.tsx b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.test.tsx
index b45a54e79..4bea0bf47 100644
--- a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.test.tsx
+++ b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.test.tsx
@@ -33,8 +33,6 @@ vi.mock('../queries/useHelmRepositories', () => ({
],
isInitialLoading: false,
isError: false,
- isFetching: false,
- refetch: vi.fn(() => Promise.resolve([])),
})),
useHelmRepositories: vi.fn(() => ({
data: ['repo1', 'repo2'],
@@ -83,8 +81,6 @@ describe('UpgradeButton', () => {
data,
isInitialLoading: false,
isError: false,
- isFetching: false,
- refetch: vi.fn(() => Promise.resolve([])),
});
renderButton();
@@ -98,8 +94,6 @@ describe('UpgradeButton', () => {
data: [],
isInitialLoading: true,
isError: false,
- isFetching: false,
- refetch: vi.fn(() => Promise.resolve([])),
});
renderButton();
@@ -115,8 +109,6 @@ describe('UpgradeButton', () => {
data,
isInitialLoading: false,
isError: false,
- isFetching: false,
- refetch: vi.fn(() => Promise.resolve([])),
});
renderButton();
@@ -147,8 +139,6 @@ describe('UpgradeButton', () => {
],
isInitialLoading: false,
isError: false,
- isFetching: false,
- refetch: vi.fn(() => Promise.resolve([])),
});
renderButton({ release: mockRelease });
diff --git a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.tsx b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.tsx
index 7376877e4..4c385c388 100644
--- a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.tsx
+++ b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeButton.tsx
@@ -1,6 +1,5 @@
import { ArrowUp } from 'lucide-react';
import { useRouter } from '@uirouter/react';
-import { useState } from 'react';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { notifySuccess } from '@/portainer/services/notifications';
@@ -42,19 +41,16 @@ export function UpgradeButton({
const updateHelmReleaseMutation = useUpdateHelmReleaseMutation(environmentId);
const repositoriesQuery = useHelmRepositories();
- const [useCache, setUseCache] = useState(true);
const helmRepoVersionsQuery = useHelmRepoVersions(
release?.chart.metadata?.name || '',
60 * 60 * 1000, // 1 hour
- repositoriesQuery.data,
- useCache
+ repositoriesQuery.data
);
const versions = helmRepoVersionsQuery.data;
// Combined loading state
const isInitialLoading =
repositoriesQuery.isInitialLoading ||
- helmRepoVersionsQuery.isFetching ||
helmRepoVersionsQuery.isInitialLoading;
const isError = repositoriesQuery.isError || helmRepoVersionsQuery.isError;
@@ -62,10 +58,9 @@ export function UpgradeButton({
select: (data) => data.chart.metadata?.version,
});
const latestVersionAvailable = versions[0]?.Version ?? '';
- const isNewVersionAvailable = Boolean(
+ const isNewVersionAvailable =
latestVersion?.data &&
- semverCompare(latestVersionAvailable, latestVersion?.data) === 1
- );
+ semverCompare(latestVersionAvailable, latestVersion?.data) === 1;
const editableHelmRelease: UpdateHelmReleasePayload = {
name: releaseName,
@@ -75,14 +70,6 @@ export function UpgradeButton({
version: release?.chart.metadata?.version,
};
- function handleRefreshVersions() {
- if (useCache === false) {
- helmRepoVersionsQuery.refetch();
- } else {
- setUseCache(false);
- }
- }
-
return (
)}
- {!isInitialLoading && !isError && (
+ {versions.length === 0 && !isInitialLoading && !isError && (
- {getStatusMessage(
- versions.length === 0,
- latestVersionAvailable,
- isNewVersionAvailable
- )}
- {versions.length === 0 && (
-
- Portainer is unable to find any versions for this chart in the
- repositories saved. Try adding a new repository which contains
- the chart in the{' '}
-
- Helm repositories settings
-
-
- }
- />
- )}
-
+ No versions available
+
+ Portainer is unable to find any versions for this chart in the
+ repositories saved. Try adding a new repository which contains
+ the chart in the{' '}
+
+ Helm repositories settings
+
+
+ }
+ />
+
+ )}
+ {isNewVersionAvailable && (
+
+ New version available ({latestVersionAvailable})
)}
@@ -185,18 +164,4 @@ export function UpgradeButton({
},
});
}
-
- function getStatusMessage(
- hasNoAvailableVersions: boolean,
- latestVersionAvailable: string,
- isNewVersionAvailable: boolean
- ): string {
- if (hasNoAvailableVersions) {
- return 'No versions available ';
- }
- if (isNewVersionAvailable) {
- return `New version available (${latestVersionAvailable}) `;
- }
- return '';
- }
}
diff --git a/app/react/kubernetes/helm/HelmApplicationView/queries/useHelmRepositories.ts b/app/react/kubernetes/helm/HelmApplicationView/queries/useHelmRepositories.ts
index bf11eadb1..733b79dea 100644
--- a/app/react/kubernetes/helm/HelmApplicationView/queries/useHelmRepositories.ts
+++ b/app/react/kubernetes/helm/HelmApplicationView/queries/useHelmRepositories.ts
@@ -45,21 +45,20 @@ export function useHelmRepositories() {
export function useHelmRepoVersions(
chart: string,
staleTime: number,
- repositories: string[] = [],
- useCache: boolean = true
+ repositories: string[] = []
) {
// 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),
+ queryKey: ['helm', 'repositories', chart, repo],
+ queryFn: () => getSearchHelmRepo(repo, chart),
enabled: !!chart && repositories.length > 0,
staleTime,
...withGlobalError(`Unable to retrieve versions from ${repo}`),
})),
- [repositories, chart, staleTime, useCache]
+ [repositories, chart, staleTime]
),
});
@@ -73,8 +72,6 @@ export function useHelmRepoVersions(
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())),
};
}
@@ -83,12 +80,11 @@ export function useHelmRepoVersions(
*/
async function getSearchHelmRepo(
repo: string,
- chart: string,
- useCache: boolean = true
+ chart: string
): Promise {
try {
const { data } = await axios.get(`templates/helm`, {
- params: { repo, chart, useCache },
+ params: { repo, chart },
});
const versions = data.entries[chart];
return (
diff --git a/pkg/libhelm/options/search_repo_options.go b/pkg/libhelm/options/search_repo_options.go
index 0b35c0bbd..73acc5709 100644
--- a/pkg/libhelm/options/search_repo_options.go
+++ b/pkg/libhelm/options/search_repo_options.go
@@ -3,8 +3,6 @@ package options
import "net/http"
type SearchRepoOptions struct {
- Repo string `example:"https://charts.gitlab.io/"`
- Client *http.Client `example:"&http.Client{Timeout: time.Second * 10}"`
- Chart string `example:"my-chart"`
- UseCache bool `example:"false"`
+ Repo string `example:"https://charts.gitlab.io/"`
+ Client *http.Client `example:"&http.Client{Timeout: time.Second * 10}"`
}
diff --git a/pkg/libhelm/sdk/search_repo.go b/pkg/libhelm/sdk/search_repo.go
index 63015330c..90dd98529 100644
--- a/pkg/libhelm/sdk/search_repo.go
+++ b/pkg/libhelm/sdk/search_repo.go
@@ -4,8 +4,6 @@ import (
"net/url"
"os"
"path/filepath"
- "sync"
- "time"
"github.com/pkg/errors"
"github.com/portainer/portainer/pkg/libhelm/options"
@@ -27,17 +25,6 @@ type RepoIndex struct {
Generated string `json:"generated"`
}
-type RepoIndexCache struct {
- Index *repo.IndexFile
- Timestamp time.Time
-}
-
-var (
- indexCache = make(map[string]RepoIndexCache)
- cacheMutex sync.RWMutex
- cacheDuration = 60 * time.Minute
-)
-
// SearchRepo downloads the `index.yaml` file for specified repo, parses it and returns JSON to caller.
func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoOptions) ([]byte, error) {
// Validate input options
@@ -66,18 +53,6 @@ func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoO
return nil, err
}
- // Check cache first
- if searchRepoOpts.UseCache {
- cacheMutex.RLock()
- if cached, exists := indexCache[repoURL.String()]; exists {
- if time.Since(cached.Timestamp) < cacheDuration {
- cacheMutex.RUnlock()
- return convertAndMarshalIndex(cached.Index, searchRepoOpts.Chart)
- }
- }
- cacheMutex.RUnlock()
- }
-
// Set up Helm CLI environment
repoSettings := cli.New()
@@ -117,21 +92,23 @@ func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoO
return nil, err
}
- // Update cache and remove old entries
- cacheMutex.Lock()
- indexCache[searchRepoOpts.Repo] = RepoIndexCache{
- Index: indexFile,
- Timestamp: time.Now(),
- }
- for key, index := range indexCache {
- if time.Since(index.Timestamp) > cacheDuration {
- delete(indexCache, key)
- }
+ // Convert the index file to our response format
+ result, err := convertIndexToResponse(indexFile)
+ if err != nil {
+ log.Error().
+ Str("context", "HelmClient").
+ Err(err).
+ Msg("Failed to convert index to response format")
+ return nil, errors.Wrap(err, "failed to convert index to response format")
}
- cacheMutex.Unlock()
+ log.Debug().
+ Str("context", "HelmClient").
+ Str("repo", searchRepoOpts.Repo).
+ Int("entries_count", len(indexFile.Entries)).
+ Msg("Successfully searched repository")
- return convertAndMarshalIndex(indexFile, searchRepoOpts.Chart)
+ return json.Marshal(result)
}
// validateSearchRepoOptions validates the required search repository options.
@@ -239,7 +216,7 @@ func loadIndexFile(indexPath string) (*repo.IndexFile, error) {
}
// convertIndexToResponse converts the Helm index file to our response format.
-func convertIndexToResponse(indexFile *repo.IndexFile, chartName string) (RepoIndex, error) {
+func convertIndexToResponse(indexFile *repo.IndexFile) (RepoIndex, error) {
result := RepoIndex{
APIVersion: indexFile.APIVersion,
Entries: make(map[string][]ChartInfo),
@@ -248,9 +225,7 @@ func convertIndexToResponse(indexFile *repo.IndexFile, chartName string) (RepoIn
// Convert Helm SDK types to our response types
for name, charts := range indexFile.Entries {
- if chartName == "" || name == chartName {
- result.Entries[name] = convertChartsToChartInfo(charts)
- }
+ result.Entries[name] = convertChartsToChartInfo(charts)
}
return result, nil
@@ -374,23 +349,3 @@ func ensureHelmDirectoriesExist(settings *cli.EnvSettings) error {
return nil
}
-
-func convertAndMarshalIndex(indexFile *repo.IndexFile, chartName string) ([]byte, error) {
- // Convert the index file to our response format
- result, err := convertIndexToResponse(indexFile, chartName)
- if err != nil {
- log.Error().
- Str("context", "HelmClient").
- Err(err).
- Msg("Failed to convert index to response format")
- return nil, errors.Wrap(err, "failed to convert index to response format")
- }
-
- log.Debug().
- Str("context", "HelmClient").
- Str("repo", chartName).
- Int("entries_count", len(indexFile.Entries)).
- Msg("Successfully searched repository")
-
- return json.Marshal(result)
-}