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

Feat: Implement rendering of dock tab content

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
Iku-turso 2023-04-14 15:50:04 +03:00 committed by Janne Savolainen
parent 934784c588
commit 88bf456cea
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
9 changed files with 194 additions and 38 deletions

View File

@ -7,19 +7,68 @@ exports[`DockHost, given rendered given implementations of dock tabs emerge rend
<div
class="flex align-center"
>
<div>
<div
data-dock-tab-test="some-dock-tab-1"
>
<div
data-some-dock-tab-title-test="true"
data-dock-tab-title-test="some-title-1"
>
Some title
Some title 1
</div>
</div>
<div
data-dock-tab-test="some-dock-tab-2"
>
<div
data-dock-tab-title-test="some-title-2"
>
Some title 2
</div>
</div>
</div>
<div>
<div
data-some-dock-tab-content-test="true"
data-dock-tab-content-test="some-content-1"
>
Some content
Some content 1
</div>
</div>
</div>
</div>
</body>
`;
exports[`DockHost, given rendered given implementations of dock tabs emerge when the second dock tab is clicked renders 1`] = `
<body>
<div>
<div>
<div
class="flex align-center"
>
<div
data-dock-tab-test="some-dock-tab-1"
>
<div
data-dock-tab-title-test="some-title-1"
>
Some title 1
</div>
</div>
<div
data-dock-tab-test="some-dock-tab-2"
>
<div
data-dock-tab-title-test="some-title-2"
>
Some title 2
</div>
</div>
</div>
<div>
<div
data-dock-tab-content-test="some-content-2"
>
Some content 2
</div>
</div>
</div>

View File

@ -4,6 +4,7 @@ import { renderFor } from "@k8slens/test-utils";
import { DockHost } from "./dock/dock-host";
import React from "react";
import type { RenderResult } from "@testing-library/react";
import { act } from "@testing-library/react";
import { dockTabInjectionToken } from "./dock-tab";
import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery";
import { registerFeature } from "@k8slens/feature-core";
@ -31,20 +32,38 @@ describe("DockHost, given rendered", () => {
describe("given implementations of dock tabs emerge", () => {
beforeEach(() => {
const dockTabInjectable = getInjectable({
id: "some-dock-tab",
const dockTabInjectable1 = getInjectable({
id: "some-dock-tab-1",
instantiate: () => ({
id: "some-dock-tab",
TitleComponent: () => <div data-some-dock-tab-title-test>Some title</div>,
ContentComponent: () => <div data-some-dock-tab-content-test>Some content</div>,
id: "some-dock-tab-1",
TitleComponent: () => <div data-dock-tab-title-test="some-title-1">Some title 1</div>,
ContentComponent: () => (
<div data-dock-tab-content-test="some-content-1">Some content 1</div>
),
}),
injectionToken: dockTabInjectionToken,
});
const dockTabInjectable2 = getInjectable({
id: "some-dock-tab-2",
instantiate: () => ({
id: "some-dock-tab-2",
TitleComponent: () => <div data-dock-tab-title-test="some-title-2">Some title 2</div>,
ContentComponent: () => (
<div data-dock-tab-content-test="some-content-2">Some content 2</div>
),
}),
injectionToken: dockTabInjectionToken,
});
runInAction(() => {
di.register(dockTabInjectable);
di.register(dockTabInjectable1, dockTabInjectable2);
});
});
@ -52,12 +71,35 @@ describe("DockHost, given rendered", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("renders the title of dock tab", () => {
discover.getSingleElement("some-dock-tab-title");
it("renders the titles of all the dock tabs in order", () => {
expect(discover.queryAllElements("dock-tab-title").attributeValues).toEqual([
"some-title-1",
"some-title-2",
]);
});
it("renders the content of the dock tab", () => {
discover.getSingleElement("some-dock-tab-content");
it("renders only the content of the first dock tab", () => {
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
"some-content-1",
]);
});
describe("when the second dock tab is clicked", () => {
beforeEach(() => {
act(() => {
discover.getSingleElement("dock-tab", "some-dock-tab-2").click();
});
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("renders only the content of the second dock tab", () => {
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
"some-content-2",
]);
});
});
});
});

View File

@ -0,0 +1,19 @@
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import { action } from "mobx";
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
const activateDockTabInjectable = getInjectable({
id: "activate-dock-tab",
instantiate: (di, tabId) => {
const activeDockTabId = di.inject(activeDockTabIdInjectable);
return action(() => activeDockTabId.set(tabId));
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, tabId: string) => tabId,
}),
});
export default activateDockTabInjectable;

View File

@ -0,0 +1,9 @@
import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx";
const activeDockTabIdInjectable = getInjectable({
id: "active-dock-tab-id",
instantiate: () => observable.box<string | null>(),
});
export default activeDockTabIdInjectable;

View File

@ -1,23 +1,33 @@
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import dockTabsInjectable from "./dock-tabs.injectable";
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
import { pipeline } from "@ogre-tools/fp";
import { defaults, find, first } from "lodash/fp";
import type { DockTab } from "../dock-tab";
import dockTabTypesInjectable from "./dock-tabs-types.injectable";
const nullTab: DockTab = {
id: "no-active-dock-tab",
TitleComponent: () => null,
ContentComponent: () => null,
};
const activeDockTabInjectable = getInjectable({
id: "active-dock-tab",
instantiate: (di) => {
const dockTabs = di.inject(dockTabsInjectable);
const dockTabTypes = di.inject(dockTabTypesInjectable);
const activeDockTabId = di.inject(activeDockTabIdInjectable);
return computed(() => {
const [
activeDockTab = {
id: "no-active-dock-tab",
TitleComponent: () => null,
ContentComponent: () => null,
},
] = dockTabs.get();
const tabs = dockTabTypes.get();
return activeDockTab;
return pipeline(
tabs,
find((tab) => tab.id === activeDockTabId.get()),
defaults(first(tabs)),
defaults(nullTab),
);
});
},
});

View File

@ -4,7 +4,7 @@ import { withInjectables } from "@ogre-tools/injectable-react";
import React from "react";
import { Tabs } from "./tabs";
import { Div, Map } from "@k8slens/ui-components";
import dockTabsInjectable from "./dock-tabs.injectable";
import dockTabsInjectable, { ActivatableDockTab } from "./dock-tabs.injectable";
import type { DockTab } from "../dock-tab";
import activeDockTabInjectable from "./active-dock-tab.injectable";
@ -15,8 +15,8 @@ const NonInjectedDockHost = observer(({ dockTabs, activeDockTab }: Dependencies)
<Div>
<Tabs>
<Map items={dockTabs.get()}>
{({ TitleComponent }) => (
<Tabs.Tab>
{({ id, TitleComponent, activate }) => (
<Tabs.Tab data-dock-tab-test={id} onClick={activate}>
<TitleComponent />
</Tabs.Tab>
)}
@ -31,7 +31,7 @@ const NonInjectedDockHost = observer(({ dockTabs, activeDockTab }: Dependencies)
});
interface Dependencies {
dockTabs: IComputedValue<DockTab[]>;
dockTabs: IComputedValue<ActivatableDockTab[]>;
activeDockTab: IComputedValue<DockTab>;
}

View File

@ -0,0 +1,15 @@
import { getInjectable } from "@ogre-tools/injectable";
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
import { dockTabInjectionToken } from "../dock-tab";
const dockTabTypesInjectable = getInjectable({
id: "dock-tab-types",
instantiate: (di) => {
const computedInjectMany = di.inject(computedInjectManyInjectable);
return computedInjectMany(dockTabInjectionToken);
},
});
export default dockTabTypesInjectable;

View File

@ -1,14 +1,27 @@
import { getInjectable } from "@ogre-tools/injectable";
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
import { dockTabInjectionToken } from "../dock-tab";
import { computed } from "mobx";
import type { DockTab } from "../dock-tab";
import activateDockTabInjectable from "./activate-dock-tab.injectable";
import dockTabTypesInjectable from "./dock-tabs-types.injectable";
type Activatable = { activate: () => void };
export type ActivatableDockTab = DockTab & Activatable;
const dockTabsInjectable = getInjectable({
id: "dock-tabs",
instantiate: (di) => {
const computedInjectMany = di.inject(computedInjectManyInjectable);
const dockTabTypes = di.inject(dockTabTypesInjectable);
const activateFor = di.injectFactory(activateDockTabInjectable);
return computedInjectMany(dockTabInjectionToken);
return computed(() =>
dockTabTypes.get().map((tab) => ({
...tab,
activate: activateFor(tab.id),
})),
);
},
});

View File

@ -1,5 +1,6 @@
import { Div } from "@k8slens/ui-components";
import React from "react";
import type { DivProps } from "@k8slens/ui-components";
export interface TabsProps {
children: React.ReactNode;
@ -9,12 +10,10 @@ export const Tabs = ({ children }: TabsProps) => (
<Div _flexParent={{ centeredVertically: true }}>{children}</Div>
);
export interface TabProps {
export type TabProps = {
children: React.ReactNode;
}
} & DivProps;
const Tab = ({ children }: TabProps) => (
<Div>{children}</Div>
);
const Tab = ({ ...props }: TabProps) => <Div {...props} />;
Tabs.Tab = Tab;