Skip to content

Commit

Permalink
Check object instanceof on all detail panels (#4054)
Browse files Browse the repository at this point in the history
* Check object instanceof on all detail panels

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix unit tests

- Remove prettier as snapShot testing is too tight of a bound

Signed-off-by: Sebastian Malton <sebastian@malton.name>
  • Loading branch information
Nokel81 committed Oct 15, 2021
1 parent dabfce3 commit 052d12f
Show file tree
Hide file tree
Showing 32 changed files with 392 additions and 168 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@
"postcss": "^8.3.6",
"postcss-loader": "4.3.0",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.4.1",
"progress-bar-webpack-plugin": "^2.1.0",
"randomcolor": "^0.6.2",
"raw-loader": "^4.0.2",
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/components/+catalog/catalog-entity-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import styles from "./catalog.module.css";
import React from "react";
import { action, computed } from "mobx";
import type { CatalogEntity } from "../../api/catalog-entity";
import { CatalogEntity } from "../../api/catalog-entity";
import type { ItemObject } from "../../../common/item.store";
import { Badge } from "../badge";
import { navigation } from "../../navigation";
Expand All @@ -33,7 +33,11 @@ import type { CatalogEntityRegistry } from "../../api/catalog-entity-registry";
const css = makeCss(styles);

export class CatalogEntityItem<T extends CatalogEntity> implements ItemObject {
constructor(public entity: T, private registry: CatalogEntityRegistry) {}
constructor(public entity: T, private registry: CatalogEntityRegistry) {
if (!(entity instanceof CatalogEntity)) {
throw Object.assign(new TypeError("CatalogEntityItem cannot wrap a non-CatalogEntity type"), { typeof: typeof entity, prototype: Object.getPrototypeOf(entity) });
}
}

get kind() {
return this.entity.kind;
Expand Down
112 changes: 35 additions & 77 deletions src/renderer/components/+catalog/catalog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Catalog } from "./catalog";
import { createMemoryHistory } from "history";
import { mockWindow } from "../../../../__mocks__/windowMock";
import { kubernetesClusterCategory } from "../../../common/catalog-entities/kubernetes-cluster";
import { catalogCategoryRegistry, CatalogCategoryRegistry } from "../../../common/catalog";
import { catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntity, CatalogEntityActionContext, CatalogEntityData } from "../../../common/catalog";
import { CatalogEntityRegistry } from "../../../renderer/api/catalog-entity-registry";
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
import { CatalogEntityItem } from "./catalog-entity-item";
Expand All @@ -46,6 +46,18 @@ jest.mock("@electron/remote", () => {
};
});

class MockCatalogEntity extends CatalogEntity {
public apiVersion = "api";
public kind = "kind";

constructor(data: CatalogEntityData, public onRun: (context: CatalogEntityActionContext) => void | Promise<void>) {
super(data);
}

public onContextMenuOpen(): void | Promise<void> {}
public onSettingsOpen(): void | Promise<void> {}
}

describe("<Catalog />", () => {
const history = createMemoryHistory();
const mockLocation = {
Expand All @@ -66,30 +78,21 @@ describe("<Catalog />", () => {
url: "",
};

const catalogEntityUid = "a_catalogEntity_uid";
const catalogEntity = {
enabled: true,
apiVersion: "api",
kind: "kind",
metadata: {
uid: catalogEntityUid,
name: "a catalog entity",
labels: {
test: "label",
function createMockCatalogEntity(onRun: (context: CatalogEntityActionContext) => void | Promise<void>) {
return new MockCatalogEntity({
metadata: {
uid: "a_catalogEntity_uid",
name: "a catalog entity",
labels: {
test: "label",
},
},
},
status: {
phase: "",
},
spec: {},
};
const catalogEntityItemMethods = {
getId: () => catalogEntity.metadata.uid,
getName: () => catalogEntity.metadata.name,
onContextMenuOpen: () => {},
onSettingsOpen: () => {},
onRun: () => {},
};
status: {
phase: "",
},
spec: {},
}, onRun);
}

beforeEach(() => {
CatalogEntityDetailRegistry.createInstance();
Expand Down Expand Up @@ -117,11 +120,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand All @@ -130,29 +129,8 @@ describe("<Catalog />", () => {

catalogEntityRegistry.addOnBeforeRun(
(event) => {
expect(event.target).toMatchInlineSnapshot(`
Object {
"apiVersion": "api",
"enabled": true,
"getId": [Function],
"getName": [Function],
"kind": "kind",
"metadata": Object {
"labels": Object {
"test": "label",
},
"name": "a catalog entity",
"uid": "a_catalogEntity_uid",
},
"onContextMenuOpen": [Function],
"onRun": [MockFunction],
"onSettingsOpen": [Function],
"spec": Object {},
"status": Object {
"phase": "",
},
}
`);
expect(event.target.getId()).toBe("a_catalogEntity_uid");
expect(event.target.getName()).toBe("a catalog entity");

setTimeout(() => {
expect(onRun).toHaveBeenCalled();
Expand All @@ -178,11 +156,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand Down Expand Up @@ -216,11 +190,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand Down Expand Up @@ -255,11 +225,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn(() => done());
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand Down Expand Up @@ -289,11 +255,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand Down Expand Up @@ -330,11 +292,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem({
...catalogEntity,
...catalogEntityItemMethods,
onRun,
}, catalogEntityRegistry);
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);

// mock as if there is a selected item > the detail panel opens
jest
Expand Down
26 changes: 16 additions & 10 deletions src/renderer/components/+config-autoscalers/hpa-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { Table, TableCell, TableHead, TableRow } from "../table";
import { apiManager } from "../../../common/k8s-api/api-manager";
import { KubeObjectMeta } from "../kube-object-meta";
import { getDetailsUrl } from "../kube-detail-params";
import logger from "../../../common/logger";

export interface HpaDetailsProps extends KubeObjectDetailsProps<HorizontalPodAutoscaler> {
}
Expand Down Expand Up @@ -80,17 +81,13 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
<TableCell className="metrics">Current / Target</TableCell>
</TableHead>
{
hpa.getMetrics().map((metric, index) => {
const name = renderName(metric);
const values = hpa.getMetricValues(metric);

return (
hpa.getMetrics()
.map((metric, index) => (
<TableRow key={index}>
<TableCell className="name">{name}</TableCell>
<TableCell className="metrics">{values}</TableCell>
<TableCell className="name">{renderName(metric)}</TableCell>
<TableCell className="metrics">{hpa.getMetricValues(metric)}</TableCell>
</TableRow>
);
})
))
}
</Table>
);
Expand All @@ -99,7 +96,16 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
render() {
const { object: hpa } = this.props;

if (!hpa) return null;
if (!hpa) {
return null;
}

if (!(hpa instanceof HorizontalPodAutoscaler)) {
logger.error("[HpaDetails]: passed object that is not an instanceof HorizontalPodAutoscaler", hpa);

return null;
}

const { scaleTargetRef } = hpa.spec;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { LimitPart, LimitRange, LimitRangeItem, Resource } from "../../../common
import { KubeObjectMeta } from "../kube-object-meta";
import { DrawerItem } from "../drawer/drawer-item";
import { Badge } from "../badge";
import logger from "../../../common/logger";

interface Props extends KubeObjectDetailsProps<LimitRange> {
}
Expand Down Expand Up @@ -57,23 +58,30 @@ function renderResourceLimits(limit: LimitRangeItem, resource: Resource) {

function renderLimitDetails(limits: LimitRangeItem[], resources: Resource[]) {

return resources.map(resource =>
return resources.map(resource => (
<DrawerItem key={resource} name={resource}>
{
limits.map(limit =>
renderResourceLimits(limit, resource)
)
limits.map(limit => renderResourceLimits(limit, resource))
}
</DrawerItem>
);
));
}

@observer
export class LimitRangeDetails extends React.Component<Props> {
render() {
const { object: limitRange } = this.props;

if (!limitRange) return null;
if (!limitRange) {
return null;
}

if (!(limitRange instanceof LimitRange)) {
logger.error("[LimitRangeDetails]: passed object that is not an instanceof LimitRange", limitRange);

return null;
}

const containerLimits = limitRange.getContainerLimits();
const podLimits = limitRange.getPodLimits();
const pvcLimits = limitRange.getPVCLimits();
Expand Down
42 changes: 25 additions & 17 deletions src/renderer/components/+config-maps/config-map-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ import { Input } from "../input";
import { Button } from "../button";
import { configMapsStore } from "./config-maps.store";
import type { KubeObjectDetailsProps } from "../kube-object-details";
import type { ConfigMap } from "../../../common/k8s-api/endpoints";
import { ConfigMap } from "../../../common/k8s-api/endpoints";
import { KubeObjectMeta } from "../kube-object-meta";
import logger from "../../../common/logger";

interface Props extends KubeObjectDetailsProps<ConfigMap> {
}
Expand Down Expand Up @@ -82,7 +83,16 @@ export class ConfigMapDetails extends React.Component<Props> {
render() {
const { object: configMap } = this.props;

if (!configMap) return null;
if (!configMap) {
return null;
}

if (!(configMap instanceof ConfigMap)) {
logger.error("[ConfigMapDetails]: passed object that is not an instanceof ConfigMap", configMap);

return null;
}

const data = Array.from(this.data.entries());

return (
Expand All @@ -93,22 +103,20 @@ export class ConfigMapDetails extends React.Component<Props> {
<>
<DrawerTitle title="Data"/>
{
data.map(([name, value]) => {
return (
<div key={name} className="data">
<div className="name">{name}</div>
<div className="flex gaps align-flex-start">
<Input
multiLine
theme="round-black"
className="box grow"
value={value}
onChange={v => this.data.set(name, v)}
/>
</div>
data.map(([name, value]) => (
<div key={name} className="data">
<div className="name">{name}</div>
<div className="flex gaps align-flex-start">
<Input
multiLine
theme="round-black"
className="box grow"
value={value}
onChange={v => this.data.set(name, v)}
/>
</div>
);
})
</div>
))
}
<Button
primary
Expand Down
Loading

0 comments on commit 052d12f

Please sign in to comment.