Skip to content

Commit

Permalink
Catalog v2 (#1865)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andres Martinez Gotor committed Jul 17, 2020
1 parent 454f4e2 commit 6d7daa3
Show file tree
Hide file tree
Showing 37 changed files with 1,303 additions and 55 deletions.
3 changes: 2 additions & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"json-schema": "^0.2.5",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.19",
"lodash-es": "^4.17.15",
"mem": "^4.0.0",
"moniker-native": "^0.1.6",
"prop-types": "15.7.2",
Expand Down Expand Up @@ -149,7 +150,7 @@
"!src/**/*.d.ts"
],
"transformIgnorePatterns": [
"node_modules/(?!@clr|lit-element|lit-html|ramda|.*css)"
"node_modules/(?!@clr|lit-element|lit-html|ramda|lodash-es|.*css)"
]
},
"eslintConfig": {
Expand Down
5 changes: 0 additions & 5 deletions dashboard/src/components/AppList/AppList.v2.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
.kubeapps-applist-header {
width: 100%;
padding: 0 0.6rem 0 0.6rem;
}

.header-button {
display: flex;
justify-content: flex-end;
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/AppList/AppList.v2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function AppList(props: IAppListProps) {
return (
<section>
<PageHeader>
<div className="kubeapps-applist-header">
<div className="kubeapps-header">
<Row>
<Column span={10}>
<Row>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ function CustomResourceListItem(props: ICustomResourceListItemProps) {
title={resource.metadata.name}
icon={icon}
description={crd.description}
info={`${resource.kind} v${csv.spec.version || "-"}`}
info={
<>
<div>{resource.kind}</div>
<div>v{csv.spec.version || "-"}</div>
</>
}
tag1Content={csv.metadata.name.split(".")[0]}
subIcon={operatorIcon}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`when an error is present matches the snapshot 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -68,7 +68,7 @@ exports[`when an error is present renders a generic error message 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -132,7 +132,7 @@ exports[`when apps available matches the snapshot 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -209,7 +209,7 @@ exports[`when custom resources available matches the snapshot 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -299,7 +299,7 @@ exports[`when fetched but not apps available matches the snapshot 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -364,7 +364,7 @@ exports[`while fetching apps loading spinner matches the snapshot 1`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down Expand Up @@ -428,7 +428,7 @@ exports[`while fetching apps loading spinner matches the snapshot 2`] = `
<section>
<PageHeader>
<div
className="kubeapps-applist-header"
className="kubeapps-header"
>
<Row
list={false}
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/Card/CardGrid.v2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Row from "../js/Row";

import "./CardGrid.v2.css";

function CardGrid(props: { children: JSX.Element }) {
function CardGrid(props: { children: JSX.Element | JSX.Element[] }) {
return (
<div className="card-grid">
<Row>{props.children}</Row>
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/Catalog/Catalog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CatalogItem, {
IOperatorCatalogItem,
} from "./CatalogItem";

interface ICatalogProps {
export interface ICatalogProps {
charts: IChartState;
repo: string;
filter: string;
Expand Down
30 changes: 30 additions & 0 deletions dashboard/src/components/Catalog/Catalog.v2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.filters-menu {
padding-left: 1.2rem;
h5 {
text-transform: uppercase;
font-size: small;
font-weight: 500;
}
.filter-section {
font-weight: 500;
margin: 0.7rem 0 0.5rem 0;
}
}

.empty-catalog {
text-align: center;
width: 100%;
height: calc(100vh - 6rem);
// margin-top: 2rem;
cds-icon {
margin-top: 2rem;
width: 4rem;
height: 4rem;
}
cds-button {
margin-top: 2rem;
}
p {
margin-top: 0.6rem;
}
}
198 changes: 198 additions & 0 deletions dashboard/src/components/Catalog/Catalog.v2.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import context from "jest-plugin-context";
import * as React from "react";

import FilterGroup from "components/FilterGroup/FilterGroup";
import InfoCard from "components/InfoCard/InfoCard.v2";
import Alert from "components/js/Alert";
import { act } from "react-dom/test-utils";
import { defaultStore, mountWrapper } from "shared/specs/mountWrapper";
import itBehavesLike from "../../shared/specs";
import { IChart, IChartState, IClusterServiceVersion } from "../../shared/types";
import SearchFilter from "../SearchFilter/SearchFilter.v2";
import Catalog from "./Catalog.v2";

const defaultChartState = {
isFetching: false,
selected: {} as IChartState["selected"],
deployed: {} as IChartState["deployed"],
items: [],
updatesInfo: {},
} as IChartState;
const defaultProps = {
charts: defaultChartState,
repo: "",
filter: "",
fetchCharts: jest.fn(),
pushSearchFilter: jest.fn(),
namespace: "kubeapps",
kubeappsNamespace: "kubeapps",
csvs: [],
getCSVs: jest.fn(),
featureFlags: { operators: false, additionalClusters: [], ui: "hex" },
};
const chartItem = {
id: "foo",
attributes: {
name: "foo",
description: "",
repo: { name: "foo", namespace: "chart-namespace" },
},
relationships: { latestChartVersion: { data: { app_version: "v1.0.0" } } },
} as IChart;
const chartItem2 = {
id: "bar",
attributes: {
name: "bar",
description: "",
repo: { name: "bar", namespace: "chart-namespace" },
},
relationships: { latestChartVersion: { data: { app_version: "v2.0.0" } } },
} as IChart;
const csv = {
metadata: {
name: "test-csv",
},
spec: {
provider: {
name: "me",
},
icon: [{ base64data: "data", mediatype: "img/png" }],
customresourcedefinitions: {
owned: [
{
name: "foo-cluster",
displayName: "foo-cluster",
version: "v1.0.0",
description: "a meaningful description",
},
],
},
},
} as IClusterServiceVersion;
const populatedProps = {
...defaultProps,
csvs: [csv],
charts: { ...defaultChartState, items: [chartItem, chartItem2] },
};

it("retrieves csvs in the namespace", () => {
const getCSVs = jest.fn();
mountWrapper(defaultStore, <Catalog {...populatedProps} getCSVs={getCSVs} />);
expect(getCSVs).toHaveBeenCalledWith(defaultProps.namespace);
});

it("shows all the elements", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} />);
expect(wrapper.find(InfoCard)).toHaveLength(3);
});

it("should render a message if there are no elements in the catalog", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...defaultProps} />);
const message = wrapper.find(".empty-catalog");
expect(message).toExist();
expect(message).toIncludeText("The current catalog is empty");
});

it("should render an error if it exists", () => {
const charts = {
...defaultChartState,
selected: {
error: new Error("Boom!"),
},
} as any;
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} charts={charts} />);
const error = wrapper.find(Alert);
expect(error.prop("theme")).toBe("danger");
expect(error).toIncludeText("Boom!");
});

context("when fetching apps", () => {
itBehavesLike("aLoadingComponent", {
component: Catalog,
props: { ...defaultProps, charts: { isFetching: true, items: [], selected: {} } },
});
});

describe("filters by the searched item", () => {
it("filters using prop", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} filter={"bar"} />);
expect(wrapper.find(InfoCard)).toHaveLength(1);
});

it("filters modifying the search box", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} />);
act(() => {
(wrapper.find(SearchFilter).prop("onChange") as any)("bar");
});
wrapper.update();
expect(wrapper.find(InfoCard)).toHaveLength(1);
});
});

describe("filters by application type", () => {
it("doesn't show the filter if there are no csvs", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} csvs={[]} />);
expect(wrapper.find(FilterGroup).findWhere(g => g.prop("name") === "apptype")).not.toExist();
});

it("filters only charts", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} />);
const input = wrapper.find("input").findWhere(i => i.prop("value") === "Charts");
input.simulate("change", { target: { value: "Charts" } });
wrapper.update();
expect(wrapper.find(InfoCard)).toHaveLength(2);
});

it("filters only operators", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} />);
const input = wrapper.find("input").findWhere(i => i.prop("value") === "Operators");
input.simulate("change", { target: { value: "Operators" } });
wrapper.update();
expect(wrapper.find(InfoCard)).toHaveLength(1);
});
});

describe("filters by application repository", () => {
it("doesn't show the filter if there are no apps", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...defaultProps} />);
expect(wrapper.find(FilterGroup).findWhere(g => g.prop("name") === "apprepo")).not.toExist();
});

it("filters by repo", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} />);
// The repo name is "foo"
const input = wrapper.find("input").findWhere(i => i.prop("value") === "foo");
input.simulate("change", { target: { value: "foo" } });
wrapper.update();
expect(wrapper.find(InfoCard)).toHaveLength(1);
});
});

describe("filters by operator provider", () => {
it("doesn't show the filter if there are no csvs", () => {
const wrapper = mountWrapper(defaultStore, <Catalog {...defaultProps} />);
expect(
wrapper.find(FilterGroup).findWhere(g => g.prop("name") === "operator-provider"),
).not.toExist();
});

it("filters by operator provider", () => {
const csv2 = {
metadata: {
name: "csv2",
},
spec: {
...csv.spec,
provider: {
name: "you",
},
},
} as any;
const wrapper = mountWrapper(defaultStore, <Catalog {...populatedProps} csvs={[csv, csv2]} />);
// The repo name is "foo"
const input = wrapper.find("input").findWhere(i => i.prop("value") === "you");
input.simulate("change", { target: { value: "you" } });
wrapper.update();
expect(wrapper.find(InfoCard)).toHaveLength(1);
});
});

0 comments on commit 6d7daa3

Please sign in to comment.