From 123f674e2f71d10aaf7c7004b7e1b798c8331695 Mon Sep 17 00:00:00 2001 From: Andrey Pokhilko Date: Tue, 17 Mar 2026 15:09:11 +0200 Subject: [PATCH] feat: install and upgrade charts from URLs (#663) * feat: add support for installing and upgrading charts from URLs Adds "Install from URL" button to the repositories page, allowing users to install charts directly from OCI registries and other URLs without adding them as repositories first. Also adds URL mode to the upgrade modal (via pencil/X toggle) for charts not found in any configured repo. Closes #660 Co-Authored-By: Claude Opus 4.6 (1M context) * Alter --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../InstallReleaseChartModal.tsx | 58 ++++++++++++-- .../InstallRepoChartModal.tsx | 75 +++++++++++++++---- .../repository/RepositoriesList.tsx | 23 ++++++ 3 files changed, 134 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx index 3ac9388..50eea86 100644 --- a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx +++ b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx @@ -9,6 +9,8 @@ import { } from "react"; import { useParams } from "react-router"; +import { BsPencil, BsX } from "react-icons/bs"; + import apiService from "../../../API/apiService"; import type { LatestChartVersion } from "../../../API/interfaces"; import { @@ -88,7 +90,10 @@ export const InstallReleaseChartModal = ({ const selectedVersion = selectedVersionData?.version || ""; const selectedRepo = selectedVersionData?.repository || ""; - const chartAddress = useMemo(() => { + const [chartURL, setChartURL] = useState(""); + const [useURLMode, setUseURLMode] = useState(false); + + const repoChartAddress = useMemo(() => { if (!selectedVersionData || !selectedVersionData.repository) return ""; return selectedVersionData.urls?.[0]?.startsWith("file://") @@ -96,6 +101,8 @@ export const InstallReleaseChartModal = ({ : `${selectedVersionData.repository}/${chartName}`; }, [selectedVersionData, chartName]); + const chartAddress = useURLMode ? chartURL : repoChartAddress || chartURL; + // the original chart values const { data: chartValues = "" } = useChartRepoValues({ version: selectedVersion, @@ -216,13 +223,48 @@ export const InstallReleaseChartModal = ({ }, ]} > - {versions && isNoneEmptyArray(versions) && ( - + {!useURLMode && versions && isNoneEmptyArray(versions) ? ( +
+ + +
+ ) : ( +
+
+

Chart URL:

+ setChartURL(e.target.value)} + placeholder="oci://registry-1.docker.io/example/chart" + /> +
+ {versions && isNoneEmptyArray(versions) && ( + + )} +
)} { + urlMode: initialURLMode = false, +}: InstallChartModalProps & { urlMode?: boolean }) => { const navigate = useNavigateWithSearchParams(); const [userValues, setUserValues] = useState(""); const [installError, setInstallError] = useState(""); @@ -83,7 +86,10 @@ export const InstallRepoChartModal = ({ const selectedRepo = selectedVersionData?.repository; - const chartAddress = useMemo(() => { + const [chartURL, setChartURL] = useState(""); + const [useURLMode, setUseURLMode] = useState(initialURLMode); + + const repoChartAddress = useMemo(() => { if (!selectedVersionData || !selectedVersionData?.repository) { return ""; } @@ -92,6 +98,8 @@ export const InstallRepoChartModal = ({ : `${selectedVersionData?.repository}/${chartName}`; }, [selectedVersionData, chartName]); + const chartAddress = useURLMode ? chartURL : repoChartAddress || chartURL; + const { data: chartValues = "", isLoading: loadingChartValues } = useChartRepoValues({ version: selectedVersion || "", @@ -175,11 +183,15 @@ export const InstallRepoChartModal = ({ onClose(); }} title={ - + initialURLMode ? ( +
Install from URL
+ ) : ( + + ) } containerClassNames="w-full text-2xl h-2/3" actions={[ @@ -195,13 +207,48 @@ export const InstallRepoChartModal = ({ }, ]} > - {versions && isNoneEmptyArray(versions) && ( - + {!useURLMode && versions && isNoneEmptyArray(versions) ? ( +
+ + +
+ ) : ( +
+
+

Chart URL:

+ setChartURL(e.target.value)} + placeholder="oci://registry-1.docker.io/example/chart:1.0.0" + /> +
+ {versions && isNoneEmptyArray(versions) && ( + + )} +
)} { + if (value) { + upsertSearchParams("install_url", "true"); + } else { + removeSearchParam("install_url"); + } + }; return ( <> @@ -61,6 +70,14 @@ function RepositoriesList({ > + Add Repository +

Charts developers: you can also add local directories as chart source. Use{" "} @@ -72,6 +89,12 @@ function RepositoriesList({ isOpen={showAddRepositoryModal} onClose={() => setShowAddRepositoryModal(false)} /> + setShowInstallURLModal(false)} + chartName="" + urlMode + /> ); }