From 1df25ffe2b7fa562670a076234b2e810a5ba8ce9 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Thu, 17 Dec 2020 12:52:34 +0200 Subject: [PATCH] Parse jsonPath properly Signed-off-by: Lauri Nevala --- .../crd-resource-details.tsx | 3 ++- .../+custom-resources/crd-resources.tsx | 18 ++++++++++----- .../utils/__tests__/jsonPath.test.tsx | 22 +++++++++++++++++++ src/renderer/utils/jsonPath.ts | 21 ++++++++++++++++++ 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 src/renderer/utils/__tests__/jsonPath.test.tsx create mode 100644 src/renderer/utils/jsonPath.ts diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index 3dc03f5fe0..412293eee1 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -13,6 +13,7 @@ import { crdStore } from "./crd.store"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Input } from "../input"; import { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import { parseJsonPath } from "../../utils/jsonPath"; interface Props extends KubeObjectDetailsProps { } @@ -46,7 +47,7 @@ export class CrdResourceDetails extends React.Component { renderAdditionalColumns(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { return columns.map(({ name, jsonPath: jp }) => ( - {convertSpecValue(jsonPath.value(crd, `$..["${jp.slice(1).replace(/\\/g, "")}"]`))} + {convertSpecValue(jsonPath.value(crd, parseJsonPath(jp.slice(1))))} )); } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index 7502298cf3..6725ecb975 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -12,6 +12,7 @@ import { autorun, computed } from "mobx"; import { crdStore } from "./crd.store"; import { TableSortCallback } from "../table"; import { apiManager } from "../../api/api-manager"; +import { parseJsonPath } from "../../utils/jsonPath"; interface Props extends RouteComponentProps { } @@ -61,7 +62,7 @@ export class CrdResources extends React.Component { }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, `$..["${column.jsonPath.slice(1).replace(/\\/g, "")}"]`); + sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); }); return ( @@ -91,10 +92,17 @@ export class CrdResources extends React.Component { renderTableContents={(crdInstance: KubeObject) => [ crdInstance.getName(), isNamespaced && crdInstance.getNs(), - ...extraColumns.map(column => ({ - renderBoolean: true, - children: jsonPath.value(crdInstance, `$..["${column.jsonPath.slice(1).replace(/\\/g, "")}"]`), - })), + ...extraColumns.map((column) => { + const pathExpression = parseJsonPath(column.jsonPath.slice(1)); + + console.log(pathExpression); + + return { + renderBoolean: true, + children: jsonPath.value(crdInstance, pathExpression.replace(/\\/g, "")), + }; + } + ), crdInstance.getAge(), ]} /> diff --git a/src/renderer/utils/__tests__/jsonPath.test.tsx b/src/renderer/utils/__tests__/jsonPath.test.tsx new file mode 100644 index 0000000000..f456cc3a15 --- /dev/null +++ b/src/renderer/utils/__tests__/jsonPath.test.tsx @@ -0,0 +1,22 @@ +import { parseJsonPath } from "../jsonPath"; + +describe("parseJsonPath", () => { + test("should convert \. to use indexed notation", () => { + const res = parseJsonPath(".metadata.labels.kubesphere\\.io/alias-name"); + + expect(res).toBe(".metadata['labels']['kubesphere.io/alias-name']"); + + }); + + test("strips '\' away from the result", () => { + const res = parseJsonPath(".metadata.labels['serving\\.knative\\.dev/configuration']"); + + expect(res).toBe(".metadata.labels['serving.knative.dev/configuration']"); + }); + + test("should not touch given jsonPath if no invalid characters", () => { + const res = parseJsonPath(".status.conditions[?(@.type=='Ready')].status"); + + expect(res).toBe(".status.conditions[?(@.type=='Ready')].status"); + }); +}); diff --git a/src/renderer/utils/jsonPath.ts b/src/renderer/utils/jsonPath.ts new file mode 100644 index 0000000000..d3ba34e6ce --- /dev/null +++ b/src/renderer/utils/jsonPath.ts @@ -0,0 +1,21 @@ + +export function parseJsonPath(jsonPath: string) { + let pathExpression = jsonPath; + + if (!jsonPath.includes("[") && jsonPath.includes("\\")) { + // convert cases where \. is present to use indexed notation, + // for example: .metadata.labels.kubesphere\.io/alias-name -> .metadata['labels']['kubesphere\.io/alias-name'] + const columnArr = jsonPath.split(/(?<=\w)\./); + + columnArr.forEach((value, index) => { + if (index == 0) { + pathExpression = `${value}`; + } else { + pathExpression += `['${value}']`; + } + }); + } + + // strip '\' characters from the result + return pathExpression.replace(/\\/g, ""); +} \ No newline at end of file