diff --git a/src/renderer/api/__tests__/kube-api-parse.test.ts b/src/renderer/api/__tests__/kube-api-parse.test.ts index beb8df8221..18b805212d 100644 --- a/src/renderer/api/__tests__/kube-api-parse.test.ts +++ b/src/renderer/api/__tests__/kube-api-parse.test.ts @@ -129,8 +129,18 @@ const tests: KubeApiParseTestData[] = [ }], ]; +const throwtests = [ + undefined, + "", + "ajklsmh" +]; + describe("parseApi unit tests", () => { - it.each(tests)("testing %s", (url, expected) => { + it.each(tests)("testing %j", (url, expected) => { expect(parseKubeApi(url)).toStrictEqual(expected); }); + + it.each(throwtests)("testing %j should throw", (url) => { + expect(() => parseKubeApi(url)).toThrowError("invalid apiPath"); + }); }); diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index eafcf0d8ee..9477446386 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -58,8 +58,14 @@ export class ApiManager { } } - protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api); + protected resolveApi(api?: string | KubeApi): KubeApi | undefined { + if (!api) { + return undefined; + } + + if (typeof api === "string") { + return this.getApi(api); + } return api; } diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index b02067fb63..10e280d6c8 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -24,6 +24,9 @@ import type { KubeObject } from "./kube-object"; import { splitArray } from "../../common/utils"; import { apiManager } from "./api-manager"; +import { isDebugging } from "../../common/vars"; +import logger from "../../main/logger"; +import { inspect } from "util"; export interface IKubeObjectRef { kind: string; @@ -47,8 +50,26 @@ export interface IKubeApiParsed extends IKubeApiLinkRef { } export function parseKubeApi(path: string): IKubeApiParsed { - path = new URL(path, location.origin).pathname; - const [, prefix, ...parts] = path.split("/"); + if (!isDebugging) { + return _parseKubeApi(path); + } + + try { + const res = _parseKubeApi(path); + + logger.debug(`parseKubeApi(${inspect(path, false, null, false)}) -> ${inspect(res, false, null, false)}`); + + return res; + } catch (error) { + logger.debug(`parseKubeApi(${inspect(path, false, null, false)}) threw: ${error}`); + + throw error; + } +} + +function _parseKubeApi(path: string): IKubeApiParsed { + const apiPath = new URL(path, location.origin).pathname; + const [, prefix, ...parts] = apiPath.split("/"); const apiPrefix = `/${prefix}`; const [left, right, namespaced] = splitArray(parts, "namespaces"); let apiGroup, apiVersion, namespace, resource, name; @@ -70,12 +91,14 @@ export function parseKubeApi(path: string): IKubeApiParsed { apiGroup = left.join("/"); } else { switch (left.length) { + case 0: + throw new Error(`invalid apiPath: ${apiPath}`); case 4: [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); - // fallthrough + // fallthrough case 1: apiVersion = left.pop(); apiGroup = ""; @@ -113,7 +136,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`); + throw new Error(`invalid apiPath: ${apiPath}`); } return { diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index 8098f77064..1f0c494b4e 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -34,6 +34,7 @@ import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMenu } from "./kube-object-menu"; import type { CustomResourceDefinition } from "../../api/endpoints"; import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; +import logger from "../../../main/logger"; /** * Used to store `object.selfLink` to show more info about resource in the details panel. @@ -67,6 +68,7 @@ export function hideDetails() { } export function getDetailsUrl(selfLink: string, resetSelected = false, mergeGlobals = true) { + logger.debug("getDetailsUrl", { selfLink, resetSelected, mergeGlobals }); const params = new URLSearchParams(mergeGlobals ? navigation.searchParams : ""); params.set(kubeDetailsUrlParam.name, selfLink); @@ -100,10 +102,12 @@ export class KubeObjectDetails extends React.Component { } @computed get object() { - const store = apiManager.getStore(this.path); - - if (store) { - return store.getByPath(this.path); + try { + return apiManager + .getStore(this.path) + ?.getByPath(this.path); + } catch (error) { + logger.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path }); } }