mirror of
https://github.com/komodorio/helm-dashboard.git
synced 2026-03-24 11:48:04 +00:00
Merge branch 'main' of github.com:komodorio/helm-dashboard
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
20
frontend/package-lock.json
generated
20
frontend/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -43,6 +43,8 @@ export interface ApplicationStatus {
|
||||
ClusterMode: boolean;
|
||||
CurVer: string;
|
||||
LatestVer: string;
|
||||
NoHealth: boolean;
|
||||
NoLatest: boolean;
|
||||
}
|
||||
|
||||
export interface KubectlContexts {
|
||||
|
||||
@@ -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<ReleaseHealthStatus[]>({
|
||||
queryKey: ["resourceStatus", release],
|
||||
queryFn: () => apiService.getResourceStatus({ release }),
|
||||
enabled: inView,
|
||||
enabled: inView && !status?.NoHealth,
|
||||
});
|
||||
|
||||
const latestVersionData: LatestChartVersion | undefined =
|
||||
|
||||
@@ -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()}`;
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function Tabs({ tabs, selectedTab }: TabsProps) {
|
||||
const moveTab = (tab: Tab) => {
|
||||
upsertSearchParams("tab", tab.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex pb-2">
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -104,6 +104,8 @@ export type Status = {
|
||||
Analytics: boolean;
|
||||
CacheHitRatio: number;
|
||||
ClusterMode: boolean;
|
||||
NoHealth: boolean;
|
||||
NoLatest: boolean;
|
||||
};
|
||||
|
||||
export type ChartVersion = {
|
||||
|
||||
@@ -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() {
|
||||
<ul className="flex w-full items-center md:mt-0 md:flex-row md:justify-between md:border-0 md:text-sm md:font-normal">
|
||||
<li>
|
||||
<LinkWithSearchParams
|
||||
to={"installed"}
|
||||
to={"/installed"}
|
||||
exclude={["tab"]}
|
||||
className={getBtnStyle("installed")}
|
||||
>
|
||||
@@ -85,7 +86,7 @@ export default function Header() {
|
||||
</li>
|
||||
<li>
|
||||
<LinkWithSearchParams
|
||||
to={"repository"}
|
||||
to={"/repository"}
|
||||
exclude={["tab"]}
|
||||
end={false}
|
||||
className={getBtnStyle("repository")}
|
||||
@@ -124,7 +125,9 @@ export default function Header() {
|
||||
]}
|
||||
/>
|
||||
</li>
|
||||
{"v" + statusData?.CurVer !== statusData?.LatestVer ? (
|
||||
{statusData?.CurVer &&
|
||||
statusData?.LatestVer &&
|
||||
isNewerVersion(statusData.CurVer, statusData.LatestVer) ? (
|
||||
<li className="min-w-[130px]">
|
||||
<a
|
||||
href="https://github.com/komodorio/helm-dashboard/releases"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useEffect, useEffectEvent, useCallback } from "react";
|
||||
import { useMemo, useEffect, useCallback } from "react";
|
||||
|
||||
import RepositoriesList from "../components/repository/RepositoriesList";
|
||||
import RepositoryViewer from "../components/repository/RepositoryViewer";
|
||||
@@ -11,7 +11,7 @@ import useNavigateWithSearchParams from "../hooks/useNavigateWithSearchParams";
|
||||
function RepositoryPage() {
|
||||
const { selectedRepo: repoFromParams, context } = useParams();
|
||||
const navigate = useNavigateWithSearchParams();
|
||||
const { setSelectedRepo, selectedRepo } = useAppContext();
|
||||
const { setSelectedRepo } = useAppContext();
|
||||
|
||||
const navigateTo = useCallback(
|
||||
async (url: string, ...restArgs: NavigateOptions[]) => {
|
||||
@@ -31,28 +31,14 @@ function RepositoryPage() {
|
||||
setSelectedRepo(repoFromParams);
|
||||
}
|
||||
}, [setSelectedRepo, repoFromParams]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedRepo && !repoFromParams) {
|
||||
void navigateTo(`/repository/${selectedRepo}`, {
|
||||
replace: true,
|
||||
});
|
||||
}
|
||||
}, [selectedRepo, repoFromParams, context, navigateTo]);
|
||||
|
||||
const { data: repositories = [], isSuccess } = useGetRepositories();
|
||||
|
||||
const onSuccess = useEffectEvent(() => {
|
||||
if (repositories && repositories.length && !repoFromParams) {
|
||||
handleRepositoryChanged(repositories[0]);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (repositories.length && isSuccess) {
|
||||
onSuccess();
|
||||
if (repositories.length && isSuccess && !repoFromParams) {
|
||||
const firstRepo = repositories[0];
|
||||
void navigateTo(`/repository/${firstRepo.name}`, { replace: true });
|
||||
}
|
||||
}, [repositories, isSuccess]);
|
||||
}, [repositories, isSuccess, repoFromParams, context, navigateTo]);
|
||||
|
||||
const selectedRepository = useMemo(() => {
|
||||
if (repoFromParams) {
|
||||
|
||||
@@ -193,9 +193,9 @@
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@cypress/request@^3.0.0":
|
||||
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.yarnpkg.com/@cypress/request/-/request-3.0.10.tgz#e09c695e8460a82acafe6cfaf089cf2ca06dc054"
|
||||
integrity sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
@@ -210,7 +210,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"
|
||||
@@ -5602,10 +5602,10 @@ punycode@^2.1.0:
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
|
||||
qs@6.14.0:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz"
|
||||
integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
|
||||
qs@~6.14.1:
|
||||
version "6.14.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159"
|
||||
integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==
|
||||
dependencies:
|
||||
side-channel "^1.1.0"
|
||||
|
||||
@@ -5744,9 +5744,9 @@ react-refresh@^0.18.0:
|
||||
integrity sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==
|
||||
|
||||
react-router@^7.9.6:
|
||||
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.yarnpkg.com/react-router/-/react-router-7.12.0.tgz#459a86862abbedd02e76e686751fe71f9fd73a4f"
|
||||
integrity sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==
|
||||
dependencies:
|
||||
cookie "^1.0.1"
|
||||
set-cookie-parser "^2.6.0"
|
||||
|
||||
4
main.go
4
main.go
@@ -34,6 +34,8 @@ type options struct {
|
||||
Namespace string `short:"n" long:"namespace" description:"Namespace for HELM operations"`
|
||||
Devel bool `long:"devel" description:"Include development versions of charts"`
|
||||
LocalChart []string `long:"local-chart" description:"Specify location of local chart to include into UI"`
|
||||
NoHealth bool `long:"no-health" description:"Disable health checks for installed charts"`
|
||||
NoLatest bool `long:"no-latest" description:"Disable latest version checks for installed charts"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -62,6 +64,8 @@ func main() {
|
||||
NoTracking: opts.NoTracking,
|
||||
Devel: opts.Devel,
|
||||
LocalCharts: opts.LocalChart,
|
||||
NoHealth: opts.NoHealth,
|
||||
NoLatest: opts.NoLatest,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@@ -148,7 +148,7 @@ func (h *HelmHandler) Resources(c *gin.Context) {
|
||||
//return
|
||||
}
|
||||
|
||||
if c.Query("health") != "" { // we need to query k8s for health status
|
||||
if c.Query("health") != "" && !h.Data.StatusInfo.NoHealth { // we need to query k8s for health status
|
||||
app := h.GetApp(c)
|
||||
if app == nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
@@ -216,6 +216,11 @@ func (h *HelmHandler) RepoLatestVer(c *gin.Context) {
|
||||
return // sets error inside
|
||||
}
|
||||
|
||||
if h.Data.StatusInfo.NoLatest {
|
||||
c.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
rep, err := app.Repositories.Containing(qp.Name)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
|
||||
@@ -41,6 +41,8 @@ type StatusInfo struct {
|
||||
Analytics bool
|
||||
CacheHitRatio float64
|
||||
ClusterMode bool
|
||||
NoHealth bool
|
||||
NoLatest bool
|
||||
}
|
||||
|
||||
func NewDataLayer(ns []string, ver string, cg HelmConfigGetter, devel bool) (*DataLayer, error) {
|
||||
|
||||
@@ -29,6 +29,8 @@ type Server struct {
|
||||
NoTracking bool
|
||||
Devel bool
|
||||
LocalCharts []string
|
||||
NoHealth bool
|
||||
NoLatest bool
|
||||
}
|
||||
|
||||
func (s *Server) StartServer(ctx context.Context, cancel context.CancelFunc) (string, utils.ControlChan, error) {
|
||||
@@ -40,6 +42,9 @@ func (s *Server) StartServer(ctx context.Context, cancel context.CancelFunc) (st
|
||||
data.LocalCharts = s.LocalCharts
|
||||
data.StatusInfo.Analytics = (!s.NoTracking && s.Version != "0.0.0") || utils.EnvAsBool("HD_DEV_ANALYTICS", false)
|
||||
|
||||
data.StatusInfo.NoHealth = s.NoHealth || utils.EnvAsBool("HD_NO_HEALTH", false)
|
||||
data.StatusInfo.NoLatest = s.NoLatest || utils.EnvAsBool("HD_NO_LATEST", false)
|
||||
|
||||
err = s.detectClusterMode(data)
|
||||
if err != nil {
|
||||
return "", nil, errorx.Decorate(err, "Failed to detect cluster mode")
|
||||
|
||||
Reference in New Issue
Block a user