mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Extract Map, Gutter and add-separator from monolith
Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
parent
effdd1cf60
commit
b6e44424b7
@ -9,7 +9,7 @@ import type { Discriminable } from "../../../../common/utils/composable-responsi
|
||||
import type { Labelable } from "../../../../common/utils/composable-responsibilities/labelable/labelable";
|
||||
import type { MaybeShowable } from "../../../../common/utils/composable-responsibilities/showable/showable";
|
||||
import type { Orderable } from "../../../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
import type { GetSeparator } from "../../../../common/utils/add-separator/add-separator";
|
||||
import type { GetSeparator } from "@k8slens/utilities";
|
||||
import type { Composite } from "../../../../common/utils/composite/get-composite/get-composite";
|
||||
|
||||
export type ChildrenAreSeparated =
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { identity, map } from "lodash/fp";
|
||||
import React from "react";
|
||||
import type { GetSeparator } from "../../../common/utils/add-separator/add-separator";
|
||||
import { addSeparator } from "../../../common/utils/add-separator/add-separator";
|
||||
import type { GetSeparator } from "@k8slens/utilities";
|
||||
import { addSeparator } from "@k8slens/utilities";
|
||||
|
||||
interface RequiredPropertiesForItem {
|
||||
id: string;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
export { uiComponentsFeature } from "./src/feature";
|
||||
|
||||
export * from "./src/element/elements";
|
||||
export * from "./src/map/map";
|
||||
export * from "./src/gutter/gutter";
|
||||
|
||||
@ -35,15 +35,17 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@k8slens/feature-core": "^6.5.0-alpha.0",
|
||||
"@k8slens/utilities": "^1.0.0-alpha.1",
|
||||
"@ogre-tools/fp": "^15.1.2",
|
||||
"@ogre-tools/injectable": "^15.1.2",
|
||||
"@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2",
|
||||
"@ogre-tools/fp": "^15.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@async-fn/jest": "^1.6.4",
|
||||
"@k8slens/eslint-config": "6.5.0-alpha.1",
|
||||
"@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0"
|
||||
"@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0",
|
||||
"@testing-library/react": "^12.1.5"
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Gutter "when size is md", renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="w-6 h-6"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Gutter "when size is not set", renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="w-6 h-6"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Gutter "when size is sm", renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Gutter "when size is xl", renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="w-10 h-10"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
|
||||
import { Gutter, GutterProps } from "./Gutter";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
interface Scenario {
|
||||
name: string;
|
||||
props: GutterProps;
|
||||
}
|
||||
|
||||
describe("Gutter", () => {
|
||||
(
|
||||
[
|
||||
{ name: "when size is not set", props: {} },
|
||||
{ name: "when size is sm", props: { size: "sm" } },
|
||||
{ name: "when size is md", props: { size: "md" } },
|
||||
{ name: "when size is xl", props: { size: "xl" } },
|
||||
] as Scenario[]
|
||||
).forEach((scenario) => {
|
||||
it(`"${scenario.name}", renders`, () => {
|
||||
const rendered = render(<Gutter {...scenario.props} />);
|
||||
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import type { ShirtSize } from "../shirt-size";
|
||||
|
||||
export interface GutterProps {
|
||||
size?: ShirtSize;
|
||||
}
|
||||
|
||||
const classNamesByShirtSize: Record<ShirtSize, string> = {
|
||||
sm: "w-4 h-4",
|
||||
md: "w-6 h-6",
|
||||
xl: "w-10 h-10",
|
||||
};
|
||||
|
||||
export const Gutter = ({ size = "md" }: GutterProps) => (
|
||||
<div className={classNamesByShirtSize[size]} />
|
||||
);
|
||||
@ -0,0 +1,90 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Map given items and placeholder but no separator renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="some-item-id"
|
||||
/>
|
||||
<div
|
||||
data-testid="some-other-item-id"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Map given more than one item and separator renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="some-item-id"
|
||||
/>
|
||||
<div
|
||||
data-testid="separator"
|
||||
>
|
||||
Some separator
|
||||
</div>
|
||||
<div
|
||||
data-testid="some-other-item-id"
|
||||
/>
|
||||
<div
|
||||
data-testid="separator"
|
||||
>
|
||||
Some separator
|
||||
</div>
|
||||
<div
|
||||
data-testid="some-another-item-id"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Map given more than one item and separator using left and right renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="some-item-id"
|
||||
/>
|
||||
<div
|
||||
data-testid="separator-between-some-item-id-and-some-other-item-id"
|
||||
>
|
||||
Some separator between
|
||||
some-item-id
|
||||
and
|
||||
some-other-item-id
|
||||
</div>
|
||||
<div
|
||||
data-testid="some-other-item-id"
|
||||
/>
|
||||
<div
|
||||
data-testid="separator-between-some-other-item-id-and-some-another-item-id"
|
||||
>
|
||||
Some separator between
|
||||
some-other-item-id
|
||||
and
|
||||
some-another-item-id
|
||||
</div>
|
||||
<div
|
||||
data-testid="some-another-item-id"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Map given no items and placeholder renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="some-placeholder"
|
||||
>
|
||||
Some placeholder
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Map given no items but no placeholder renders 1`] = `
|
||||
<body>
|
||||
<div />
|
||||
</body>
|
||||
`;
|
||||
147
packages/technical-features/ui-components/src/map/map.test.tsx
Normal file
147
packages/technical-features/ui-components/src/map/map.test.tsx
Normal file
@ -0,0 +1,147 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { render } from "@testing-library/react";
|
||||
import React from "react";
|
||||
import { Map } from "./map";
|
||||
|
||||
describe("Map", () => {
|
||||
describe("given no items and placeholder", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = render(
|
||||
<Map
|
||||
items={[]}
|
||||
getPlaceholder={() => <div data-testid="some-placeholder">Some placeholder</div>}
|
||||
>
|
||||
{() => <div data-testid="some-row">Irrelevant</div>}
|
||||
</Map>,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders placeholder", () => {
|
||||
expect(rendered.getByTestId("some-placeholder")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not render rows", () => {
|
||||
expect(rendered.queryByTestId("some-row")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no items but no placeholder", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = render(<Map items={[]}>{() => <div data-testid="some-row">Irrelevant</div>}</Map>);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not render rows", () => {
|
||||
expect(rendered.queryByTestId("some-row")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given items and placeholder but no separator", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = render(
|
||||
<Map
|
||||
items={[{ id: "some-item-id" }, { id: "some-other-item-id" }]}
|
||||
getPlaceholder={() => <div data-testid="some-placeholder">Some placeholder</div>}
|
||||
>
|
||||
{(item) => <div data-testid={item.id} />}
|
||||
</Map>,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not render placeholder", () => {
|
||||
expect(rendered.queryByTestId("some-placeholder")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders items", () => {
|
||||
expect(rendered.getByTestId("some-item-id")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given more than one item and separator", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = render(
|
||||
<Map
|
||||
items={[
|
||||
{ id: "some-item-id" },
|
||||
{ id: "some-other-item-id" },
|
||||
{ id: "some-another-item-id" },
|
||||
]}
|
||||
getSeparator={() => <div data-testid="separator">Some separator</div>}
|
||||
>
|
||||
{(item) => <div data-testid={item.id} />}
|
||||
</Map>,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders items", () => {
|
||||
expect(rendered.getByTestId("some-item-id")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders separator", () => {
|
||||
expect(rendered.getAllByTestId("separator")).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given more than one item and separator using left and right", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = render(
|
||||
<Map
|
||||
items={[
|
||||
{ id: "some-item-id" },
|
||||
{ id: "some-other-item-id" },
|
||||
{ id: "some-another-item-id" },
|
||||
]}
|
||||
getSeparator={(left, right) => (
|
||||
<div data-testid={`separator-between-${left.id}-and-${right.id}`}>
|
||||
Some separator between
|
||||
{left.id}
|
||||
and
|
||||
{right.id}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{(item) => <div data-testid={item.id} />}
|
||||
</Map>,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders items", () => {
|
||||
expect(rendered.getByTestId("some-item-id")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders separator", () => {
|
||||
expect(
|
||||
rendered.getByTestId("separator-between-some-item-id-and-some-other-item-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
50
packages/technical-features/ui-components/src/map/map.tsx
Normal file
50
packages/technical-features/ui-components/src/map/map.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { identity, map } from "lodash/fp";
|
||||
import React from "react";
|
||||
import { addSeparator, GetSeparator } from "@k8slens/utilities";
|
||||
|
||||
interface RequiredPropertiesForItem {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface MapProps<Item extends RequiredPropertiesForItem> {
|
||||
items: Item[];
|
||||
children: (item: Item) => React.ReactElement;
|
||||
getPlaceholder?: () => React.ReactElement;
|
||||
getSeparator?: GetSeparator<Item, React.ReactElement>;
|
||||
}
|
||||
|
||||
export const Map = <Item extends RequiredPropertiesForItem>(props: MapProps<Item>) => {
|
||||
const { items, getPlaceholder, getSeparator, children } = props;
|
||||
|
||||
if (items.length === 0) {
|
||||
return getPlaceholder?.() || null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{pipeline(
|
||||
items,
|
||||
|
||||
map((item) => ({ item, render: () => children(item) })),
|
||||
|
||||
getSeparator
|
||||
? (items) =>
|
||||
addSeparator(
|
||||
(left, right) => ({
|
||||
item: {
|
||||
id: `separator-between-${left.item.id}-and-${right.item.id}`,
|
||||
},
|
||||
|
||||
render: () => getSeparator(left.item, right.item),
|
||||
}),
|
||||
|
||||
items,
|
||||
)
|
||||
: identity,
|
||||
|
||||
map(({ render, item }) => <React.Fragment key={item.id}>{render()}</React.Fragment>),
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
export type ShirtSize = "sm" | "md" | "xl";
|
||||
@ -43,3 +43,4 @@ export * from "./src/types";
|
||||
export * from "./src/union-env-path";
|
||||
export * from "./src/wait";
|
||||
export * from "./src/with-concurrency-limit";
|
||||
export * from "./src/add-separator/add-separator";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user