mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 05:19:39 +02:00
feat(helm): filter on chart versions at API level [R8S-324] (#747)
This commit is contained in:
parent
b96328e098
commit
a80b185e10
6 changed files with 153 additions and 51 deletions
|
@ -33,6 +33,8 @@ vi.mock('../queries/useHelmRepositories', () => ({
|
|||
],
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
refetch: vi.fn(() => Promise.resolve([])),
|
||||
})),
|
||||
useHelmRepositories: vi.fn(() => ({
|
||||
data: ['repo1', 'repo2'],
|
||||
|
@ -81,6 +83,8 @@ describe('UpgradeButton', () => {
|
|||
data,
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
refetch: vi.fn(() => Promise.resolve([])),
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
@ -94,6 +98,8 @@ describe('UpgradeButton', () => {
|
|||
data: [],
|
||||
isInitialLoading: true,
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
refetch: vi.fn(() => Promise.resolve([])),
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
@ -109,6 +115,8 @@ describe('UpgradeButton', () => {
|
|||
data,
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
refetch: vi.fn(() => Promise.resolve([])),
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
@ -139,6 +147,8 @@ describe('UpgradeButton', () => {
|
|||
],
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
refetch: vi.fn(() => Promise.resolve([])),
|
||||
});
|
||||
|
||||
renderButton({ release: mockRelease });
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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';
|
||||
|
@ -41,16 +42,19 @@ 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
|
||||
repositoriesQuery.data,
|
||||
useCache
|
||||
);
|
||||
const versions = helmRepoVersionsQuery.data;
|
||||
|
||||
// Combined loading state
|
||||
const isInitialLoading =
|
||||
repositoriesQuery.isInitialLoading ||
|
||||
helmRepoVersionsQuery.isFetching ||
|
||||
helmRepoVersionsQuery.isInitialLoading;
|
||||
const isError = repositoriesQuery.isError || helmRepoVersionsQuery.isError;
|
||||
|
||||
|
@ -58,9 +62,10 @@ export function UpgradeButton({
|
|||
select: (data) => data.chart.metadata?.version,
|
||||
});
|
||||
const latestVersionAvailable = versions[0]?.Version ?? '';
|
||||
const isNewVersionAvailable =
|
||||
const isNewVersionAvailable = Boolean(
|
||||
latestVersion?.data &&
|
||||
semverCompare(latestVersionAvailable, latestVersion?.data) === 1;
|
||||
semverCompare(latestVersionAvailable, latestVersion?.data) === 1
|
||||
);
|
||||
|
||||
const editableHelmRelease: UpdateHelmReleasePayload = {
|
||||
name: releaseName,
|
||||
|
@ -70,6 +75,14 @@ export function UpgradeButton({
|
|||
version: release?.chart.metadata?.version,
|
||||
};
|
||||
|
||||
function handleRefreshVersions() {
|
||||
if (useCache === false) {
|
||||
helmRepoVersionsQuery.refetch();
|
||||
} else {
|
||||
setUseCache(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<LoadingButton
|
||||
|
@ -97,30 +110,38 @@ export function UpgradeButton({
|
|||
Checking for new versions...
|
||||
</InlineLoader>
|
||||
)}
|
||||
{versions.length === 0 && !isInitialLoading && !isError && (
|
||||
{!isInitialLoading && !isError && (
|
||||
<span className="absolute flex items-center -bottom-5 left-0 right-0 text-xs text-muted text-center whitespace-nowrap">
|
||||
No versions available
|
||||
<Tooltip
|
||||
message={
|
||||
<div>
|
||||
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{' '}
|
||||
<Link
|
||||
to="portainer.account"
|
||||
params={{ '#': 'helm-repositories' }}
|
||||
data-cy="user-settings-link"
|
||||
>
|
||||
Helm repositories settings
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{isNewVersionAvailable && (
|
||||
<span className="absolute -bottom-5 left-0 right-0 text-xs text-muted text-center whitespace-nowrap">
|
||||
New version available ({latestVersionAvailable})
|
||||
{getStatusMessage(
|
||||
versions.length === 0,
|
||||
latestVersionAvailable,
|
||||
isNewVersionAvailable
|
||||
)}
|
||||
{versions.length === 0 && (
|
||||
<Tooltip
|
||||
message={
|
||||
<div>
|
||||
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{' '}
|
||||
<Link
|
||||
to="portainer.account"
|
||||
params={{ '#': 'helm-repositories' }}
|
||||
data-cy="user-settings-link"
|
||||
>
|
||||
Helm repositories settings
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
onClick={handleRefreshVersions}
|
||||
className="text-primary hover:text-primary-light cursor-pointer bg-transparent border-0 pl-1 p-0"
|
||||
type="button"
|
||||
>
|
||||
Refresh versions
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
@ -164,4 +185,18 @@ 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 '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,20 +45,21 @@ export function useHelmRepositories() {
|
|||
export function useHelmRepoVersions(
|
||||
chart: string,
|
||||
staleTime: number,
|
||||
repositories: string[] = []
|
||||
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],
|
||||
queryFn: () => getSearchHelmRepo(repo, chart),
|
||||
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]
|
||||
[repositories, chart, staleTime, useCache]
|
||||
),
|
||||
});
|
||||
|
||||
|
@ -72,6 +73,8 @@ 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())),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,11 +83,12 @@ export function useHelmRepoVersions(
|
|||
*/
|
||||
async function getSearchHelmRepo(
|
||||
repo: string,
|
||||
chart: string
|
||||
chart: string,
|
||||
useCache: boolean = true
|
||||
): Promise<ChartVersion[]> {
|
||||
try {
|
||||
const { data } = await axios.get<HelmSearch>(`templates/helm`, {
|
||||
params: { repo, chart },
|
||||
params: { repo, chart, useCache },
|
||||
});
|
||||
const versions = data.entries[chart];
|
||||
return (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue