Huge bump of versions + husky + fixed DropDown key issue and pointer (#628)

* Bump lint-staged

* Check

* Check

* Added husky

* Check

* Check

* Check

* Check

* Check

* Check

* Check

* Check

* Fix husky

* Used * instead **/* in lint-staged

* Bump tailwindcss and related

* Added @tailwindcss/vite and removed postcss

* Added lint into staged

* Bump @babel/core and updated .prettierignore

* Removed tailwind.config.cjs

* Added ThemeInit

* Added cursor-pointer to Help dropdown

* Bump react-router

* Removed @types/uuid and react-router-dom

* Bump diff2html, prettier, @typescript-eslint/eslint-plugin, @typescript-eslint/parser

* removed vite-plugin-html-config and @babel/core

* removed "@eslint/eslintrc" and "@eslint/js"

* Removed redundant link

* Returned plugins and source to index.css

* Set dark to false in tailwindcss

* Fixed storybook

* Fixed useGetLatestVersion with correct gcTime: 0 option

* Added eslint-plugin-prettier

* Removed spaces

* ClustersList.tsx improved and type fixes for another files

* Repository.tsx improved

* Huge fix of types

* Huge fix of types missed

* Fixed type of SingleValue

* Added cursor pointer
This commit is contained in:
yuri-sakharov
2025-11-29 18:49:51 +02:00
committed by GitHub
parent 1129651e6c
commit 7572f00f7c
65 changed files with 1476 additions and 1893 deletions

View File

@@ -17,7 +17,7 @@ export const ChartValues = ({
Chart Value Reference:
</label>
<pre
className="text-base bg-chart-values p-2 rounded font-medium w-full max-h-[330px] block overflow-y-auto font-sf-mono"
className="text-base bg-chart-values p-2 rounded-sm font-medium w-full max-h-[330px] block overflow-y-auto font-sf-mono"
dangerouslySetInnerHTML={
chartValues && !loading
? {

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useParams } from "react-router";
import useDebounce from "../../../hooks/useDebounce";
export const GeneralDetails = ({
@@ -27,7 +27,7 @@ export const GeneralDetails = ({
const { context } = useParams();
const inputClassName = ` text-lg py-1 px-2 border border-1 border-gray-300 ${
disabled ? "bg-gray-200" : "bg-white "
} rounded`;
} rounded-sm`;
return (
<div className="flex gap-8">
<div>

View File

@@ -1,10 +1,11 @@
import { useParams } from "react-router-dom";
import { useMemo, useState } from "react";
import { useParams } from "react-router";
import { useEffect, useEffectEvent, useMemo, useState } from "react";
import {
useChartReleaseValues,
useGetReleaseManifest,
useGetVersions,
useVersionData,
VersionData,
} from "../../../API/releases";
import Modal, { ModalButtonStyle } from "../Modal";
import { GeneralDetails } from "./GeneralDetails";
@@ -12,7 +13,7 @@ import { ManifestDiff } from "./ManifestDiff";
import { useMutation } from "@tanstack/react-query";
import useNavigateWithSearchParams from "../../../hooks/useNavigateWithSearchParams";
import { VersionToInstall } from "./VersionToInstall";
import { isNewerVersion, isNoneEmptyArray } from "../../../utils";
import { isNoneEmptyArray } from "../../../utils";
import useCustomSearchParams from "../../../hooks/useCustomSearchParams";
import { useChartRepoValues } from "../../../API/repositories";
import { useDiffData } from "../../../API/shared";
@@ -20,18 +21,18 @@ import { InstallChartModalProps } from "../../../data/types";
import { DefinedValues } from "./DefinedValues";
import apiService from "../../../API/apiService";
import { InstallUpgradeTitle } from "./InstallUpgradeTitle";
import { LatestChartVersion } from "../../../API/interfaces";
export const InstallReleaseChartModal = ({
isOpen,
onClose,
chartName,
currentlyInstalledChartVersion,
latestVersion,
isUpgrade = false,
latestRevision,
}: InstallChartModalProps) => {
const navigate = useNavigateWithSearchParams();
const [userValues, setUserValues] = useState<string>();
const [userValues, setUserValues] = useState<string>("");
const [installError, setInstallError] = useState("");
const {
@@ -44,38 +45,37 @@ export const InstallReleaseChartModal = ({
const [namespace, setNamespace] = useState(queryNamespace || "");
const [releaseName, setReleaseName] = useState(_releaseName || "");
const { error: versionsError, data: _versions } = useGetVersions(chartName, {
select: (data) => {
return data?.sort((a, b) =>
isNewerVersion(a.version, b.version) ? 1 : -1
);
},
onSuccess: (data) => {
const empty = { version: "", repository: "", urls: [] };
return setSelectedVersionData(data[0] ?? empty);
},
const {
error: versionsError,
data: _versions = [],
isSuccess,
} = useGetVersions(chartName);
const [selectedVersionData, setSelectedVersionData] = useState<VersionData>();
const [versions, setVersions] = useState<
Array<LatestChartVersion & { isChartVersion: boolean }>
>([]);
const onSuccess = useEffectEvent(() => {
const empty = { version: "", repository: "", urls: [] };
setSelectedVersionData(_versions[0] ?? empty);
setVersions(
_versions?.map((v) => ({
...v,
isChartVersion: v.version === currentlyInstalledChartVersion,
}))
);
});
const versions = _versions?.map((v) => ({
...v,
isChartVersion: v.version === currentlyInstalledChartVersion,
}));
useEffect(() => {
if (isSuccess && _versions.length) {
onSuccess();
}
}, [isSuccess, _versions]);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
latestVersion = latestVersion ?? currentlyInstalledChartVersion; // a guard for typescript, latestVersion is always defined
const [selectedVersionData, setSelectedVersionData] = useState<{
version: string;
repository?: string;
urls: string[];
}>();
const selectedVersion = useMemo(() => {
return selectedVersionData?.version;
}, [selectedVersionData]);
const selectedRepo = useMemo(() => {
return selectedVersionData?.repository || "";
}, [selectedVersionData]);
const selectedVersion = selectedVersionData?.version || "";
const selectedRepo = selectedVersionData?.repository || "";
const chartAddress = useMemo(() => {
if (!selectedVersionData || !selectedVersionData.repository) return "";
@@ -86,13 +86,13 @@ export const InstallReleaseChartModal = ({
}, [selectedVersionData, chartName]);
// the original chart values
const { data: chartValues } = useChartRepoValues({
version: selectedVersion || "",
const { data: chartValues = "" } = useChartRepoValues({
version: selectedVersion,
chart: chartAddress,
});
// The user defined values (if any we're set)
const { data: releaseValues, isLoading: loadingReleaseValues } =
const { data: releaseValues = "", isLoading: loadingReleaseValues } =
useChartReleaseValues({
namespace,
release: String(releaseName),
@@ -100,16 +100,15 @@ export const InstallReleaseChartModal = ({
});
// This hold the selected version manifest, we use it for the diff
const { data: selectedVerData, error: selectedVerDataError } = useVersionData(
{
version: selectedVersion || "",
userValues: userValues || "",
const { data: selectedVerData = {}, error: selectedVerDataError } =
useVersionData({
version: selectedVersion,
userValues,
chartAddress,
releaseValues,
namespace,
releaseName,
}
);
});
const { data: currentVerManifest, error: currentVerManifestError } =
useGetReleaseManifest({
@@ -123,14 +122,14 @@ export const InstallReleaseChartModal = ({
error: diffError,
} = useDiffData({
selectedRepo,
versionsError: versionsError as string,
currentVerManifest,
versionsError: versionsError as unknown as string, // TODO fix it
currentVerManifest: currentVerManifest as unknown as string, // TODO fix it
selectedVerData,
chart: chartAddress,
});
// Confirm method (install)
const setReleaseVersionMutation = useMutation({
const setReleaseVersionMutation = useMutation<VersionData>({
mutationKey: [
"setVersion",
namespace,
@@ -149,8 +148,7 @@ export const InstallReleaseChartModal = ({
}
formData.append("version", selectedVersion || "");
formData.append("values", userValues || releaseValues || ""); // if userValues is empty, we use the release values
const data = await apiService.fetchWithDefaults(
return await apiService.fetchWithDefaults(
`/api/helm/releases/${
namespace ? namespace : "default"
}${`/${releaseName}`}`,
@@ -159,7 +157,6 @@ export const InstallReleaseChartModal = ({
body: formData,
}
);
return data;
},
onSuccess: async (response) => {
onClose();
@@ -187,7 +184,7 @@ export const InstallReleaseChartModal = ({
title={
<InstallUpgradeTitle
isUpgrade={isUpgrade}
releaseValues={isUpgrade || releaseValues}
releaseValues={isUpgrade || !!releaseValues}
chartName={chartName}
/>
}
@@ -197,11 +194,11 @@ export const InstallReleaseChartModal = ({
id: "1",
callback: setReleaseVersionMutation.mutate,
variant: ModalButtonStyle.info,
isLoading: setReleaseVersionMutation.isLoading,
isLoading: setReleaseVersionMutation.isPending,
disabled:
loadingReleaseValues ||
isLoadingDiff ||
setReleaseVersionMutation.isLoading,
setReleaseVersionMutation.isPending,
},
]}
>
@@ -233,11 +230,11 @@ export const InstallReleaseChartModal = ({
diff={diffData as string}
isLoading={isLoadingDiff}
error={
(currentVerManifestError as string) ||
(selectedVerDataError as string) ||
(diffError as string) ||
(currentVerManifestError as unknown as string) || // TODO fix it
(selectedVerDataError as unknown as string) ||
(diffError as unknown as string) ||
installError ||
(versionsError as string)
(versionsError as unknown as string)
}
/>
</Modal>

View File

@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom";
import { useMemo, useState } from "react";
import { useParams } from "react-router";
import { useEffect, useEffectEvent, useMemo, useState } from "react";
import { useGetVersions, useVersionData } from "../../../API/releases";
import Modal, { ModalButtonStyle } from "../Modal";
import { GeneralDetails } from "./GeneralDetails";
@@ -8,19 +8,19 @@ import { useMutation } from "@tanstack/react-query";
import { useChartRepoValues } from "../../../API/repositories";
import useNavigateWithSearchParams from "../../../hooks/useNavigateWithSearchParams";
import { VersionToInstall } from "./VersionToInstall";
import { isNewerVersion, isNoneEmptyArray } from "../../../utils";
import { isNoneEmptyArray } from "../../../utils";
import { useDiffData } from "../../../API/shared";
import { InstallChartModalProps } from "../../../data/types";
import { DefinedValues } from "./DefinedValues";
import apiService from "../../../API/apiService";
import { InstallUpgradeTitle } from "./InstallUpgradeTitle";
import { LatestChartVersion } from "../../../API/interfaces";
export const InstallRepoChartModal = ({
isOpen,
onClose,
chartName,
currentlyInstalledChartVersion,
latestVersion,
}: InstallChartModalProps) => {
const navigate = useNavigateWithSearchParams();
const [userValues, setUserValues] = useState("");
@@ -31,42 +31,46 @@ export const InstallRepoChartModal = ({
const [namespace, setNamespace] = useState("");
const [releaseName, setReleaseName] = useState(chartName);
const { error: versionsError, data: _versions } = useGetVersions(chartName, {
select: (data) => {
return data?.sort((a, b) =>
isNewerVersion(a.version, b.version) ? 1 : -1
);
},
onSuccess: (data) => {
const empty = { version: "", repository: "", urls: [] };
const versionsToRepo = data.filter(
(v) => v.repository === currentRepoCtx
);
const {
error: versionsError,
data: _versions = [],
isSuccess,
} = useGetVersions(chartName);
return setSelectedVersionData(versionsToRepo[0] ?? empty);
},
});
const [versions, setVersions] = useState<
Array<LatestChartVersion & { isChartVersion: boolean }>
>([]);
const versions = _versions?.map((v) => ({
...v,
isChartVersion: v.version === currentlyInstalledChartVersion,
}));
// eslint-disable-next-line @typescript-eslint/no-unused-vars
latestVersion = latestVersion ?? currentlyInstalledChartVersion; // a guard for typescript, latestVersion is always defined
const [selectedVersionData, setSelectedVersionData] = useState<{
version: string;
repository?: string;
urls: string[];
}>();
const selectedVersion = useMemo(() => {
return selectedVersionData?.version;
}, [selectedVersionData]);
const onSuccess = useEffectEvent(() => {
const empty = { version: "", repository: "", urls: [] };
const versionsToRepo = _versions.filter(
(v) => v.repository === currentRepoCtx
);
const selectedRepo = useMemo(() => {
return selectedVersionData?.repository;
}, [selectedVersionData]);
setSelectedVersionData(versionsToRepo[0] ?? empty);
setVersions(
_versions?.map((v) => ({
...v,
isChartVersion: v.version === currentlyInstalledChartVersion,
}))
);
});
useEffect(() => {
if (isSuccess && _versions.length) {
onSuccess();
}
}, [isSuccess, _versions]);
const selectedVersion = selectedVersionData?.version;
const selectedRepo = selectedVersionData?.repository;
const chartAddress = useMemo(() => {
if (!selectedVersionData || !selectedVersionData?.repository) {
@@ -77,15 +81,15 @@ export const InstallRepoChartModal = ({
: `${selectedVersionData?.repository}/${chartName}`;
}, [selectedVersionData, chartName]);
const { data: chartValues, isLoading: loadingChartValues } =
const { data: chartValues = "", isLoading: loadingChartValues } =
useChartRepoValues({
version: selectedVersion || "",
chart: chartAddress,
});
// This hold the selected version manifest, we use it for the diff
const { data: selectedVerData, error: selectedVerDataError } = useVersionData(
{
const { data: selectedVerData = {}, error: selectedVerDataError } =
useVersionData({
version: selectedVersion || "",
userValues,
chartAddress,
@@ -93,11 +97,8 @@ export const InstallRepoChartModal = ({
namespace,
releaseName,
isInstallRepoChart: true,
options: {
enabled: Boolean(chartAddress),
},
}
);
enabled: Boolean(chartAddress),
});
const {
data: diffData,
@@ -105,14 +106,17 @@ export const InstallRepoChartModal = ({
error: diffError,
} = useDiffData({
selectedRepo: selectedRepo || "",
versionsError: versionsError as string,
versionsError: versionsError as unknown as string, // TODO fix it
currentVerManifest: "", // current version manifest should always be empty since its a fresh install
selectedVerData,
chart: chartAddress,
});
// Confirm method (install)
const setReleaseVersionMutation = useMutation({
const setReleaseVersionMutation = useMutation<{
namespace: string;
name: string;
}>({
mutationKey: [
"setVersion",
namespace,
@@ -130,17 +134,17 @@ export const InstallRepoChartModal = ({
formData.append("version", selectedVersion || "");
formData.append("values", userValues);
formData.append("name", releaseName || "");
const data = await apiService.fetchWithDefaults(
return await apiService.fetchWithDefaults(
`/api/helm/releases/${namespace ? namespace : "default"}`,
{
method: "post",
body: formData,
}
);
return data;
},
onSuccess: async (response) => {
onSuccess: async (response: { namespace: string; name: string }) => {
onClose();
navigate(`/${response.namespace}/${response.name}/installed/revision/1`);
},
@@ -169,11 +173,11 @@ export const InstallRepoChartModal = ({
id: "1",
callback: setReleaseVersionMutation.mutate,
variant: ModalButtonStyle.info,
isLoading: setReleaseVersionMutation.isLoading,
isLoading: setReleaseVersionMutation.isPending,
disabled:
loadingChartValues ||
isLoadingDiff ||
setReleaseVersionMutation.isLoading,
setReleaseVersionMutation.isPending,
},
]}
>
@@ -205,10 +209,10 @@ export const InstallRepoChartModal = ({
diff={diffData as string}
isLoading={isLoadingDiff}
error={
(selectedVerDataError as string) ||
(diffError as string) ||
(selectedVerDataError as unknown as string) || // TODO fix it
(diffError as unknown as string) ||
installError ||
(versionsError as string)
(versionsError as unknown as string)
}
/>
</Modal>

View File

@@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import Select, { components } from "react-select";
import { FC, useMemo, useState } from "react";
import Select, { components, GroupBase, SingleValueProps } from "react-select";
import { BsCheck2 } from "react-icons/bs";
import { NonEmptyArray } from "../../../data/types";
@@ -10,7 +10,19 @@ interface Version {
urls: string[];
}
export const VersionToInstall: React.FC<{
type VersionOptionType = {
value: Omit<Version, "isChartVersion">;
label: string;
check: boolean;
};
type SpecificSingleValueProps = SingleValueProps<
VersionOptionType,
false, // IsMulti
GroupBase<VersionOptionType>
>;
export const VersionToInstall: FC<{
versions: NonEmptyArray<Version>;
initialVersion?: {
repository?: string;
@@ -78,14 +90,19 @@ export const VersionToInstall: React.FC<{
}}
value={selectedOption ?? initOpt}
components={{
SingleValue: ({ children, ...props }) => (
<components.SingleValue {...props}>
<span className="text-green-700 font-bold">{children}</span>
{props.data.check && showCurrentVersion && (
<BsCheck2 className="inline-block ml-2 text-green-700 font-bold" />
)}
</components.SingleValue>
),
SingleValue: ({ children, ...props }) => {
const OriginalSingleValue =
components.SingleValue as FC<SpecificSingleValueProps>;
return (
<OriginalSingleValue {...props}>
<span className="text-green-700 font-bold">{children}</span>
{props.data.check && showCurrentVersion && (
<BsCheck2 className="inline-block ml-2 text-green-700 font-bold" />
)}
</OriginalSingleValue>
);
},
Option: ({ children, innerProps, data }) => (
<div
className={