1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Remove legacy renderBooleans prop (#5483)

This commit is contained in:
Sebastian Malton 2022-06-02 08:59:23 -04:00 committed by GitHub
parent b86d409c92
commit d4fbab7176
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 564 additions and 66 deletions

View File

@ -10,12 +10,14 @@ import type { BaseKubeObjectCondition, KubeObjectScope } from "../kube-object";
import { KubeObject } from "../kube-object";
import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
import type { JSONSchemaProps } from "./types/json-schema-props";
interface AdditionalPrinterColumnsCommon {
name: string;
type: "integer" | "number" | "string" | "boolean" | "date";
priority: number;
description: string;
priority?: number;
format?: "int32" | "int64" | "float" | "double" | "byte" | "binary" | "date" | "date-time" | "password";
description?: string;
}
export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & {
@ -26,11 +28,15 @@ type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
JSONPath: string;
};
export interface CustomResourceValidation {
openAPIV3Schema?: JSONSchemaProps;
}
export interface CustomResourceDefinitionVersion {
name: string;
served: boolean;
storage: boolean;
schema?: object; // required in v1 but not present in v1beta
schema?: CustomResourceValidation; // required in v1 but not present in v1beta
additionalPrinterColumns?: AdditionalPrinterColumnsV1[];
}

View File

@ -0,0 +1,9 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export interface ExternalDocumentation {
description?: string;
url?: string;
}

View File

@ -0,0 +1,93 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { JsonValue } from "type-fest";
import type { ExternalDocumentation } from "./external-documentation";
export interface JSONSchemaProps {
$ref?: string;
$schema?: string;
additionalItems?: JSONSchemaProps | boolean;
additionalProperties?: JSONSchemaProps | boolean;
allOf?: JSONSchemaProps[];
anyOf?: JSONSchemaProps[];
/**
* default is a default value for undefined object fields.
* Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
* Defaulting requires spec.preserveUnknownFields to be false.
*/
_default?: object;
definitions?: Partial<Record<string, JSONSchemaProps>>;
dependencies?: Partial<Record<string, object>>;
description?: string;
_enum?: object[];
example?: JsonValue;
exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
externalDocs?: ExternalDocumentation;
/**
* format is an OpenAPI v3 format string.
* Unknown formats are ignored.
*
* The following formats are validated:
* - bsonobjectid: a bson object ID, i.e. a 24 characters hex string
* - uri: an URI as parsed by Golang net/url.ParseRequestURI
* - email: an email address as parsed by Golang net/mail.ParseAddress
* - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
* - ipv4: an IPv4 IP as parsed by Golang net.ParseIP
* - ipv6: an IPv6 IP as parsed by Golang net.ParseIP
* - cidr: a CIDR as parsed by Golang net.ParseCIDR
* - mac: a MAC address as parsed by Golang net.ParseMAC
* - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
* - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$
* - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
* - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
* - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041"
* - isbn10: an ISBN10 number string like "0321751043"
* - isbn13: an ISBN13 number string like "978-0321751041"
* - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in
* - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$
* - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
* - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559"
* - byte: base64 encoded binary data
* - password: any kind of string
* - date: a date string like "2006-01-02" as defined by full-date in RFC3339
* - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format
* - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339.
*/
format?: string;
id?: string;
items?: JSONSchemaProps | JSONSchemaProps[];
maxItems?: number;
maxLength?: number;
maxProperties?: number;
maximum?: number;
minItems?: number;
minLength?: number;
minProperties?: number;
minimum?: number;
multipleOf?: number;
not?: JSONSchemaProps;
nullable?: boolean;
oneOf?: JSONSchemaProps[];
pattern?: string;
patternProperties?: Partial<Record<string, JSONSchemaProps>>;
properties?: Partial<Record<string, JSONSchemaProps>>;
required?: Array<string>;
title?: string;
type?: string;
uniqueItems?: boolean;
x_kubernetes_embedded_resource?: boolean;
x_kubernetes_int_or_string?: boolean;
x_kubernetes_list_map_keys?: string[];
x_kubernetes_list_type?: string;
x_kubernetes_map_type?: string;
x_kubernetes_preserve_unknown_fields?: boolean;
}

View File

@ -0,0 +1,225 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<CustomResourceDetails /> with a CRD with a boolean field should display false in an additionalPrinterColumn as 'false' 1`] = `
<div>
<div
class="CrdResourceDetails MyCrd"
>
<div
class="DrawerItem"
>
<span
class="name"
>
Created
</span>
<span
class="value"
>
&lt;unknown&gt;
ago
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
first-crd
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
MyField
</span>
<span
class="value"
>
<ul>
<li>
false
</li>
</ul>
</span>
</div>
</div>
</div>
`;
exports[`<CustomResourceDetails /> with a CRD with a boolean field should display true in an additionalPrinterColumn as 'true' 1`] = `
<div>
<div
class="CrdResourceDetails MyCrd"
>
<div
class="DrawerItem"
>
<span
class="name"
>
Created
</span>
<span
class="value"
>
&lt;unknown&gt;
ago
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
first-crd
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
MyField
</span>
<span
class="value"
>
<ul>
<li>
true
</li>
</ul>
</span>
</div>
</div>
</div>
`;
exports[`<CustomResourceDetails /> with a CRD with a number field should display 0 in an additionalPrinterColumn as '0' 1`] = `
<div>
<div
class="CrdResourceDetails MyCrd"
>
<div
class="DrawerItem"
>
<span
class="name"
>
Created
</span>
<span
class="value"
>
&lt;unknown&gt;
ago
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
first-crd
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
MyField
</span>
<span
class="value"
>
<ul>
<li>
0
</li>
</ul>
</span>
</div>
</div>
</div>
`;
exports[`<CustomResourceDetails /> with a CRD with a number field should display 1234 in an additionalPrinterColumn as '1234' 1`] = `
<div>
<div
class="CrdResourceDetails MyCrd"
>
<div
class="DrawerItem"
>
<span
class="name"
>
Created
</span>
<span
class="value"
>
&lt;unknown&gt;
ago
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
first-crd
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
MyField
</span>
<span
class="value"
>
<ul>
<li>
1234
</li>
</ul>
</span>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,206 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React from "react";
import { CustomResourceDefinition } from "../../../../common/k8s-api/endpoints";
import { KubeObject } from "../../../../common/k8s-api/kube-object";
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
import type { DiRender } from "../../test-utils/renderFor";
import { renderFor } from "../../test-utils/renderFor";
import { CustomResourceDetails } from "../crd-resource-details";
describe("<CustomResourceDetails />", () => {
let render: DiRender;
beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
render = renderFor(di);
});
describe("with a CRD with a boolean field", () => {
let crd: CustomResourceDefinition;
beforeEach(() => {
crd = new CustomResourceDefinition({
apiVersion: "apiextensions.k8s.io/v1",
kind: "CustomResourceDefinition",
metadata: {
name: "my-crd",
resourceVersion: "1",
selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/my-crd",
uid: "1",
},
spec: {
versions: [{
name: "v1",
served: true,
storage: true,
schema: {
openAPIV3Schema: {
type: "object",
properties: {
spec: {
type: "object",
properties: {
"my-field": {
type: "boolean",
},
},
},
},
},
},
additionalPrinterColumns: [
{
name: "MyField",
jsonPath: ".spec.my-field",
type: "boolean",
},
],
}],
group: "stable.lens.dev",
names: {
kind: "MyCrd",
plural: "my-crds",
},
scope: "Cluster",
},
});
});
it("should display false in an additionalPrinterColumn as 'false'", () => {
const cr = new KubeObject({
apiVersion: "stable.lens.dev/v1",
kind: "MyCrd",
metadata: {
name: "first-crd",
resourceVersion: "1",
selfLink: "stable.lens.dev/v1/first-crd",
uid: "2",
},
spec: {
"my-field": false,
},
});
const result = render(<CustomResourceDetails crd={crd} object={cr} />);
expect(result.container).toMatchSnapshot();
expect(result.getByText("false")).toBeTruthy();
});
it("should display true in an additionalPrinterColumn as 'true'", () => {
const cr = new KubeObject({
apiVersion: "stable.lens.dev/v1",
kind: "MyCrd",
metadata: {
name: "first-crd",
resourceVersion: "1",
selfLink: "stable.lens.dev/v1/first-crd",
uid: "2",
},
spec: {
"my-field": true,
},
});
const result = render(<CustomResourceDetails crd={crd} object={cr} />);
expect(result.container).toMatchSnapshot();
expect(result.getByText("true")).toBeTruthy();
});
});
describe("with a CRD with a number field", () => {
let crd: CustomResourceDefinition;
beforeEach(() => {
crd = new CustomResourceDefinition({
apiVersion: "apiextensions.k8s.io/v1",
kind: "CustomResourceDefinition",
metadata: {
name: "my-crd",
resourceVersion: "1",
selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/my-crd",
uid: "1",
},
spec: {
versions: [{
name: "v1",
served: true,
storage: true,
schema: {
openAPIV3Schema: {
type: "object",
properties: {
spec: {
type: "object",
properties: {
"my-field": {
type: "number",
},
},
},
},
},
},
additionalPrinterColumns: [
{
name: "MyField",
jsonPath: ".spec.my-field",
type: "number",
},
],
}],
group: "stable.lens.dev",
names: {
kind: "MyCrd",
plural: "my-crds",
},
scope: "Cluster",
},
});
});
it("should display 0 in an additionalPrinterColumn as '0'", () => {
const cr = new KubeObject({
apiVersion: "stable.lens.dev/v1",
kind: "MyCrd",
metadata: {
name: "first-crd",
resourceVersion: "1",
selfLink: "stable.lens.dev/v1/first-crd",
uid: "2",
},
spec: {
"my-field": 0,
},
});
const result = render(<CustomResourceDetails crd={crd} object={cr} />);
expect(result.container).toMatchSnapshot();
expect(result.getByText("0")).toBeTruthy();
});
it("should display 1234 in an additionalPrinterColumn as '1234'", () => {
const cr = new KubeObject({
apiVersion: "stable.lens.dev/v1",
kind: "MyCrd",
metadata: {
name: "first-crd",
resourceVersion: "1",
selfLink: "stable.lens.dev/v1/first-crd",
uid: "2",
},
spec: {
"my-field": 1234,
},
});
const result = render(<CustomResourceDetails crd={crd} object={cr} />);
expect(result.container).toMatchSnapshot();
expect(result.getByText("1234")).toBeTruthy();
});
});
});

View File

@ -25,7 +25,7 @@ export interface CustomResourceDetailsProps extends KubeObjectDetailsProps<KubeO
crd: CustomResourceDefinition;
}
function convertSpecValue(value: any): any {
function convertSpecValue(value: unknown): React.ReactNode {
if (Array.isArray(value)) {
return (
<ul>
@ -50,18 +50,22 @@ function convertSpecValue(value: any): any {
);
}
return value;
if (
typeof value === "boolean"
|| typeof value === "string"
|| typeof value === "number"
) {
return value.toString();
}
return null;
}
@observer
export class CustomResourceDetails extends React.Component<CustomResourceDetailsProps> {
renderAdditionalColumns(resource: KubeObject, columns: AdditionalPrinterColumnsV1[]) {
return columns.map(({ name, jsonPath }) => (
<DrawerItem
key={name}
name={name}
renderBoolean
>
<DrawerItem key={name} name={name}>
{convertSpecValue(JSONPath.query(resource, convertKubectlJsonPathToNodeJsonPath(jsonPath)))}
</DrawerItem>
));

View File

@ -5,14 +5,20 @@
import "./drawer-item.scss";
import React from "react";
import { cssNames, displayBooleans } from "../../utils";
import { cssNames } from "../../utils";
export interface DrawerItemProps extends React.HTMLAttributes<HTMLDivElement> {
name: React.ReactNode;
title?: string;
labelsOnly?: boolean;
hidden?: boolean;
renderBoolean?: boolean; // show "true" or "false" for all of the children elements are "typeof boolean"
/**
* @deprecated This prop is no longer used, you should stringify the booleans yourself.
*
* This was only meant to be an internal prop anyway.
*/
renderBooleans?: boolean;
}
export function DrawerItem({
@ -22,7 +28,6 @@ export function DrawerItem({
children,
hidden = false,
className,
renderBoolean,
...elemProps
}: DrawerItemProps) {
if (hidden) {
@ -36,7 +41,7 @@ export function DrawerItem({
title={title}
>
<span className="name">{name}</span>
<span className="value">{displayBooleans(renderBoolean, children)}</span>
<span className="value">{children}</span>
</div>
);
}

View File

@ -8,7 +8,7 @@ import type { TableSortBy, TableSortParams } from "./table";
import type { ReactNode } from "react";
import React from "react";
import { autoBind, cssNames, displayBooleans } from "../../utils";
import { autoBind, cssNames } from "../../utils";
import { Icon } from "../icon";
import { Checkbox } from "../checkbox";
@ -45,11 +45,6 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
*/
isChecked?: boolean;
/**
* show "true" or "false" for all of the children elements are "typeof boolean"
*/
renderBoolean?: boolean;
/**
* column name, must be same as key in sortable object <Table sortable={}/>
*/
@ -136,7 +131,6 @@ export class TableCell extends React.Component<TableCellProps> {
_nowrap,
children,
title,
renderBoolean: displayBoolean = false,
showWithColumn,
...cellProps
} = this.props;
@ -147,7 +141,7 @@ export class TableCell extends React.Component<TableCellProps> {
nowrap: _nowrap,
sorting: _sort && typeof sortBy === "string",
});
const content = displayBooleans(displayBoolean, title || children);
const content = title || children;
return (
<div

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React from "react";
import { displayBooleans } from "../display-booleans";
describe("displayBooleans tests", () => {
it("should not do anything to div's if shouldShow is false", () => {
expect(displayBooleans(false, <div></div>)).toStrictEqual(<div></div>);
});
it("should not do anything to booleans's if shouldShow is false", () => {
expect(displayBooleans(false, true)).toStrictEqual(true);
expect(displayBooleans(false, false)).toStrictEqual(false);
});
it("should stringify booleans when shouldShow is true", () => {
expect(displayBooleans(true, true)).toStrictEqual("true");
expect(displayBooleans(true, false)).toStrictEqual("false");
});
});

View File

@ -1,20 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type React from "react";
export function displayBooleans(shouldShow: boolean | undefined, from: React.ReactNode): React.ReactNode {
if (shouldShow) {
if (typeof from === "boolean") {
return from.toString();
}
if (Array.isArray(from)) {
return from.map(node => displayBooleans(shouldShow, node));
}
}
return from;
}

View File

@ -9,7 +9,6 @@ export * from "../../common/event-emitter";
export * from "./cssNames";
export * from "./cssVar";
export * from "./display-booleans";
export * from "./display-mode";
export * from "./interval";
export * from "./isMiddleClick";