diff --git a/README.md b/README.md index 53742f8..82e1b04 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ If your port 8080 is busy, you can specify a different port to use via `--port < If you need to limit the operations to a specific namespace, please use `--namespace=...` in your command-line. You can specify multiple namespaces, separated by commas. -If you don't want the browser tab to automatically open, add `--no-browser` flag in your command line. +If you don't want the browser tab to automatically open, add `--no-browser` flag in your command-line. If you want to increase the logging verbosity and see all the debug info, use the `--verbose` flag. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 008a905..822231e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -421,9 +421,9 @@ } }, "node_modules/@cypress/request": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz", - "integrity": "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.10.tgz", + "integrity": "sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -440,7 +440,7 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "6.14.0", + "qs": "~6.14.1", "safe-buffer": "^5.1.2", "tough-cookie": "^5.0.0", "tunnel-agent": "^0.6.0", @@ -10675,9 +10675,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -10967,9 +10967,9 @@ } }, "node_modules/react-router": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz", - "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz", + "integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", diff --git a/frontend/src/API/interfaces.ts b/frontend/src/API/interfaces.ts index 8f2f3a2..3497407 100644 --- a/frontend/src/API/interfaces.ts +++ b/frontend/src/API/interfaces.ts @@ -43,6 +43,8 @@ export interface ApplicationStatus { ClusterMode: boolean; CurVer: string; LatestVer: string; + NoHealth: boolean; + NoLatest: boolean; } export interface KubectlContexts { diff --git a/frontend/src/components/InstalledPackages/InstalledPackageCard.tsx b/frontend/src/components/InstalledPackages/InstalledPackageCard.tsx index 9f5a2d0..a6c2cf8 100644 --- a/frontend/src/components/InstalledPackages/InstalledPackageCard.tsx +++ b/frontend/src/components/InstalledPackages/InstalledPackageCard.tsx @@ -16,6 +16,7 @@ import { isNewerVersion } from "../../utils"; import type { LatestChartVersion } from "../../API/interfaces"; import useNavigateWithSearchParams from "../../hooks/useNavigateWithSearchParams"; import { useInView } from "react-intersection-observer"; +import { useGetApplicationStatus } from "../../API/other"; type InstalledPackageCardProps = { release: Release; @@ -31,14 +32,17 @@ export default function InstalledPackageCard({ threshold: 0.3, triggerOnce: true, }); + const { data: status } = useGetApplicationStatus(); + const { data: latestVersionResult } = useGetLatestVersion(release.chartName, { queryKey: ["chartName", release.chartName], + enabled: !status?.NoLatest, }); const { data: statusData = [], isLoading } = useQuery({ queryKey: ["resourceStatus", release], queryFn: () => apiService.getResourceStatus({ release }), - enabled: inView, + enabled: inView && !status?.NoHealth, }); const latestVersionData: LatestChartVersion | undefined = diff --git a/frontend/src/components/LinkWithSearchParams.tsx b/frontend/src/components/LinkWithSearchParams.tsx index 42464db..708cc08 100644 --- a/frontend/src/components/LinkWithSearchParams.tsx +++ b/frontend/src/components/LinkWithSearchParams.tsx @@ -23,8 +23,10 @@ const LinkWithSearchParams = ({ let prefixedUrl = to; - if (!clusterMode) { + if (!clusterMode && context) { prefixedUrl = `/${encodeURIComponent(context)}${to}`; + } else { + prefixedUrl = to; } const url = `${prefixedUrl}/?${params.toString()}`; diff --git a/frontend/src/components/Tabs.tsx b/frontend/src/components/Tabs.tsx index 9a9a8fb..d73dc57 100644 --- a/frontend/src/components/Tabs.tsx +++ b/frontend/src/components/Tabs.tsx @@ -18,7 +18,6 @@ export default function Tabs({ tabs, selectedTab }: TabsProps) { const moveTab = (tab: Tab) => { upsertSearchParams("tab", tab.value); }; - return (
diff --git a/frontend/src/components/modal/AddRepositoryModal.tsx b/frontend/src/components/modal/AddRepositoryModal.tsx index e833cea..dba5a63 100644 --- a/frontend/src/components/modal/AddRepositoryModal.tsx +++ b/frontend/src/components/modal/AddRepositoryModal.tsx @@ -5,8 +5,8 @@ import useAlertError from "../../hooks/useAlertError"; import useCustomSearchParams from "../../hooks/useCustomSearchParams"; import { useAppContext } from "../../context/AppContext"; import { useQueryClient } from "@tanstack/react-query"; -import { useNavigate } from "react-router"; import apiService from "../../API/apiService"; +import useNavigateWithSearchParams from "../../hooks/useNavigateWithSearchParams"; interface FormKeys { name: string; @@ -33,7 +33,7 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { const [isLoading, setIsLoading] = useState(false); const alertError = useAlertError(); const { setSelectedRepo } = useAppContext(); - const navigate = useNavigate(); + const navigate = useNavigateWithSearchParams(); const queryClient = useQueryClient(); const addRepository = async () => { @@ -58,7 +58,8 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { queryKey: ["helm", "repositories"], }); setSelectedRepo(formData.name || ""); - await navigate(`/repository/${formData.name}`, { + const path = `/repository/${formData.name}`; + await navigate(path, { replace: true, }); } catch (err) { @@ -68,6 +69,13 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { }); } finally { setIsLoading(false); + setFormData({ + name: "", + url: "", + username: "", + password: "", + }); + onClose(); } }; diff --git a/frontend/src/components/revision/RevisionDetails.tsx b/frontend/src/components/revision/RevisionDetails.tsx index b36d43f..d6c77a4 100644 --- a/frontend/src/components/revision/RevisionDetails.tsx +++ b/frontend/src/components/revision/RevisionDetails.tsx @@ -335,7 +335,9 @@ const Rollback = ({ useRollbackRelease({ onSuccess: async () => { await navigate( - `/${namespace}/${chart}/installed/revision/${revisionInt + 1}` + `/${namespace}/${chart}/installed/revision/${ + installedRevision.revision + 1 + }` ); window.location.reload(); }, @@ -387,7 +389,7 @@ const Rollback = ({ rollbackRelease({ ns: namespace, name: String(chart), - revision: release.revision, + revision: rollbackRevision, }); }, variant: ModalButtonStyle.info, diff --git a/frontend/src/data/types.ts b/frontend/src/data/types.ts index 3e7b8a6..b49861e 100644 --- a/frontend/src/data/types.ts +++ b/frontend/src/data/types.ts @@ -104,6 +104,8 @@ export type Status = { Analytics: boolean; CacheHitRatio: number; ClusterMode: boolean; + NoHealth: boolean; + NoLatest: boolean; }; export type ChartVersion = { diff --git a/frontend/src/layout/Header.tsx b/frontend/src/layout/Header.tsx index 7a81fe9..fd4ace0 100644 --- a/frontend/src/layout/Header.tsx +++ b/frontend/src/layout/Header.tsx @@ -14,6 +14,7 @@ import LinkWithSearchParams from "../components/LinkWithSearchParams"; import apiService from "../API/apiService"; import { useAppContext } from "../context/AppContext"; import { useEffect, useEffectEvent } from "react"; +import { isNewerVersion } from "../utils"; export default function Header() { const { clusterMode, setClusterMode } = useAppContext(); @@ -76,7 +77,7 @@ export default function Header() {