mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
feat: Make dock tabs able to be created dynamically
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
834944141d
commit
89c08dd76f
@ -42,7 +42,8 @@
|
|||||||
"mobx-react": "^7.6.0",
|
"mobx-react": "^7.6.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^17",
|
"react": "^17",
|
||||||
"react-dom": "^17"
|
"react-dom": "^17",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@async-fn/jest": "^1.6.4",
|
"@async-fn/jest": "^1.6.4",
|
||||||
|
|||||||
@ -1,44 +1,19 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`DockHost, given rendered given implementations of dock tabs emerge renders 1`] = `
|
exports[`DockHost, given rendered given implementations of dock tab types emerge renders 1`] = `
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="flex align-center"
|
class="flex align-center"
|
||||||
>
|
/>
|
||||||
<div
|
<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-1"
|
|
||||||
>
|
|
||||||
Some content 1
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`DockHost, given rendered given implementations of dock tabs emerge when the second dock tab is clicked renders 1`] = `
|
exports[`DockHost, given rendered given implementations of dock tab types emerge when dock tab of one of the types is created given another dock tab is created when the second dock tab is clicked renders 1`] = `
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@ -46,7 +21,7 @@ exports[`DockHost, given rendered given implementations of dock tabs emerge when
|
|||||||
class="flex align-center"
|
class="flex align-center"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-dock-tab-test="some-dock-tab-1"
|
data-dock-tab-test="some-random-id-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-dock-tab-title-test="some-title-1"
|
data-dock-tab-title-test="some-title-1"
|
||||||
@ -55,7 +30,7 @@ exports[`DockHost, given rendered given implementations of dock tabs emerge when
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
data-dock-tab-test="some-dock-tab-2"
|
data-dock-tab-test="some-random-id-1"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-dock-tab-title-test="some-title-2"
|
data-dock-tab-title-test="some-title-2"
|
||||||
@ -76,7 +51,36 @@ exports[`DockHost, given rendered given implementations of dock tabs emerge when
|
|||||||
</body>
|
</body>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`DockHost, given rendered given no implementations of dock tabs, renders 1`] = `
|
exports[`DockHost, given rendered given implementations of dock tab types emerge when dock tab of one of the types is created renders 1`] = `
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="flex align-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-dock-tab-test="some-random-id-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-dock-tab-title-test="some-title-1"
|
||||||
|
>
|
||||||
|
Some title 1
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
data-dock-tab-content-test="some-content-1"
|
||||||
|
>
|
||||||
|
Some content 1
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`DockHost, given rendered given no implementations of dock tab types, renders 1`] = `
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
export type DockTab = {
|
export type DockTabType = {
|
||||||
id: string;
|
id: string;
|
||||||
TitleComponent: React.ComponentType;
|
TitleComponent: React.ComponentType;
|
||||||
ContentComponent: React.ComponentType;
|
ContentComponent: React.ComponentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dockTabInjectionToken = getInjectionToken<DockTab>({
|
export const dockTabTypeInjectionToken = getInjectionToken<DockTabType>({
|
||||||
id: "dock-tab-injection-token",
|
id: "dock-tab-type-injection-token",
|
||||||
});
|
});
|
||||||
@ -5,10 +5,38 @@ import { DockHost } from "./dock/dock-host";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import type { RenderResult } from "@testing-library/react";
|
import type { RenderResult } from "@testing-library/react";
|
||||||
import { act } from "@testing-library/react";
|
import { act } from "@testing-library/react";
|
||||||
import { dockTabInjectionToken } from "./dock-tab";
|
import { dockTabTypeInjectionToken } from "./dock-tab-type";
|
||||||
import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery";
|
import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery";
|
||||||
import { registerFeature } from "@k8slens/feature-core";
|
import { registerFeature } from "@k8slens/feature-core";
|
||||||
import { dockFeature } from "./feature";
|
import { dockFeature } from "./feature";
|
||||||
|
import { createDockTabInjectionToken } from "./dock/create-dock-tab.injectable";
|
||||||
|
import { getRandomIdInjectionToken } from "./dock/get-random-id.injectable";
|
||||||
|
|
||||||
|
const dockTabTypeInjectable1 = getInjectable({
|
||||||
|
id: "some-dock-tab-type-1",
|
||||||
|
|
||||||
|
instantiate: () => ({
|
||||||
|
id: "some-dock-tab-type-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: dockTabTypeInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dockTabTypeInjectable2 = getInjectable({
|
||||||
|
id: "some-dock-tab-type-2",
|
||||||
|
|
||||||
|
instantiate: () => ({
|
||||||
|
id: "some-dock-tab-type-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: dockTabTypeInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
describe("DockHost, given rendered", () => {
|
describe("DockHost, given rendered", () => {
|
||||||
let di: DiContainer;
|
let di: DiContainer;
|
||||||
@ -20,50 +48,26 @@ describe("DockHost, given rendered", () => {
|
|||||||
|
|
||||||
registerFeature(di, dockFeature);
|
registerFeature(di, dockFeature);
|
||||||
|
|
||||||
|
di.override(getRandomIdInjectionToken, () => {
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
return () => `some-random-id-${index++}`;
|
||||||
|
});
|
||||||
|
|
||||||
const render = renderFor(di);
|
const render = renderFor(di);
|
||||||
|
|
||||||
rendered = render(<DockHost />);
|
rendered = render(<DockHost />);
|
||||||
discover = discoverFor(() => rendered);
|
discover = discoverFor(() => rendered);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("given no implementations of dock tabs, renders", () => {
|
it("given no implementations of dock tab types, renders", () => {
|
||||||
expect(rendered.baseElement).toMatchSnapshot();
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("given implementations of dock tabs emerge", () => {
|
describe("given implementations of dock tab types emerge", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const dockTabInjectable1 = getInjectable({
|
|
||||||
id: "some-dock-tab-1",
|
|
||||||
|
|
||||||
instantiate: () => ({
|
|
||||||
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(() => {
|
runInAction(() => {
|
||||||
di.register(dockTabInjectable1, dockTabInjectable2);
|
di.register(dockTabTypeInjectable1, dockTabTypeInjectable2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -71,35 +75,83 @@ describe("DockHost, given rendered", () => {
|
|||||||
expect(rendered.baseElement).toMatchSnapshot();
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders the titles of all the dock tabs in order", () => {
|
it("renders no tabs", () => {
|
||||||
expect(discover.queryAllElements("dock-tab-title").attributeValues).toEqual([
|
const { discovered } = discover.querySingleElement("dock-tab");
|
||||||
"some-title-1",
|
|
||||||
"some-title-2",
|
expect(discovered).toBeNull();
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders only the content of the first dock tab", () => {
|
it("renders no content", () => {
|
||||||
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
|
const { discovered } = discover.querySingleElement("dock-tab-content");
|
||||||
"some-content-1",
|
|
||||||
]);
|
expect(discovered).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when the second dock tab is clicked", () => {
|
describe("when dock tab of one of the types is created", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
act(() => {
|
const dockTabType1 = di.inject(dockTabTypeInjectable1);
|
||||||
discover.getSingleElement("dock-tab", "some-dock-tab-2").click();
|
|
||||||
});
|
const createDockTab = di.inject(createDockTabInjectionToken);
|
||||||
|
|
||||||
|
createDockTab({ type: dockTabType1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
expect(rendered.baseElement).toMatchSnapshot();
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders only the content of the second dock tab", () => {
|
it("renders the title for the dock tab", () => {
|
||||||
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
|
expect(discover.queryAllElements("dock-tab-title").attributeValues).toEqual([
|
||||||
"some-content-2",
|
"some-title-1",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("renders the content of the first dock tab", () => {
|
||||||
|
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
|
||||||
|
"some-content-1",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given another dock tab is created", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const dockTabType2 = di.inject(dockTabTypeInjectable2);
|
||||||
|
|
||||||
|
const createDockTab = di.inject(createDockTabInjectionToken);
|
||||||
|
|
||||||
|
createDockTab({ type: dockTabType2 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders the titles of all the dock tabs in order of creating", () => {
|
||||||
|
expect(discover.queryAllElements("dock-tab-title").attributeValues).toEqual([
|
||||||
|
"some-title-1",
|
||||||
|
"some-title-2",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders only the content of the just created dock tab", () => {
|
||||||
|
expect(discover.queryAllElements("dock-tab-content").attributeValues).toEqual([
|
||||||
|
"some-content-2",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the second dock tab is clicked", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
act(() => {
|
||||||
|
discover.getSingleElement("dock-tab", "some-random-id-1").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",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { action } from "mobx";
|
import { action } from "mobx";
|
||||||
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
|
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
|
||||||
|
|
||||||
const activateDockTabInjectable = getInjectable({
|
const activateDockTabInjectable = getInjectable({
|
||||||
id: "activate-dock-tab",
|
id: "activate-dock-tab",
|
||||||
|
|
||||||
instantiate: (di, tabId) => {
|
instantiate: (di) => {
|
||||||
const activeDockTabId = di.inject(activeDockTabIdInjectable);
|
const activeDockTabId = di.inject(activeDockTabIdInjectable);
|
||||||
|
|
||||||
return action(() => activeDockTabId.set(tabId));
|
return action((tabId: string) => activeDockTabId.set(tabId));
|
||||||
},
|
},
|
||||||
|
|
||||||
lifecycle: lifecycleEnum.keyedSingleton({
|
|
||||||
getInstanceKey: (di, tabId: string) => tabId,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default activateDockTabInjectable;
|
export default activateDockTabInjectable;
|
||||||
|
|||||||
@ -3,24 +3,29 @@ import { computed } from "mobx";
|
|||||||
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
|
import activeDockTabIdInjectable from "./active-dock-tab-id.injectable";
|
||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { defaults, find, first } from "lodash/fp";
|
import { defaults, find, first } from "lodash/fp";
|
||||||
import type { DockTab } from "../dock-tab";
|
import dockTabsInjectable, { DockTabViewModel } from "./dock-tabs.injectable";
|
||||||
import dockTabTypesInjectable from "./dock-tabs-types.injectable";
|
|
||||||
|
|
||||||
const nullTab: DockTab = {
|
const nullTab: DockTabViewModel = {
|
||||||
id: "no-active-dock-tab",
|
id: "no-active-dock-tab",
|
||||||
TitleComponent: () => null,
|
|
||||||
ContentComponent: () => null,
|
type: {
|
||||||
|
id: "no-active-dock-tab-type",
|
||||||
|
TitleComponent: () => null,
|
||||||
|
ContentComponent: () => null,
|
||||||
|
},
|
||||||
|
|
||||||
|
activate: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const activeDockTabInjectable = getInjectable({
|
const activeDockTabInjectable = getInjectable({
|
||||||
id: "active-dock-tab",
|
id: "active-dock-tab",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const dockTabTypes = di.inject(dockTabTypesInjectable);
|
const dockTabs = di.inject(dockTabsInjectable);
|
||||||
const activeDockTabId = di.inject(activeDockTabIdInjectable);
|
const activeDockTabId = di.inject(activeDockTabIdInjectable);
|
||||||
|
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
const tabs = dockTabTypes.get();
|
const tabs = dockTabs.get();
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
tabs,
|
tabs,
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import { runInAction } from "mobx";
|
||||||
|
import type { DockTabType } from "../dock-tab-type";
|
||||||
|
import { dockTabStateInjectable } from "./dock-tab-state.injectable";
|
||||||
|
import { getRandomIdInjectionToken } from "./get-random-id.injectable";
|
||||||
|
import activateDockTabInjectable from "./activate-dock-tab.injectable";
|
||||||
|
|
||||||
|
export interface CreateDockTabParams {
|
||||||
|
type: DockTabType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateDockTab = ({ type }: CreateDockTabParams) => void;
|
||||||
|
|
||||||
|
export const createDockTabInjectionToken = getInjectionToken<CreateDockTab>({
|
||||||
|
id: "create-dock-tab-injection-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
const createDockTabInjectable = getInjectable({
|
||||||
|
id: "create-dock-tab",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const dockTabState = di.inject(dockTabStateInjectable);
|
||||||
|
const getRandomId = di.inject(getRandomIdInjectionToken);
|
||||||
|
const activateDockTab = di.inject(activateDockTabInjectable);
|
||||||
|
|
||||||
|
return ({ type }) => {
|
||||||
|
runInAction(() => {
|
||||||
|
const newTabId = getRandomId();
|
||||||
|
|
||||||
|
dockTabState.add({
|
||||||
|
id: newTabId,
|
||||||
|
typeId: type.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
activateDockTab(newTabId);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: createDockTabInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createDockTabInjectable;
|
||||||
@ -4,18 +4,19 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Tabs } from "./tabs";
|
import { Tabs } from "./tabs";
|
||||||
import { Div, Map } from "@k8slens/ui-components";
|
import { Div, Map } from "@k8slens/ui-components";
|
||||||
import dockTabsInjectable, { ActivatableDockTab } from "./dock-tabs.injectable";
|
import dockTabsInjectable, { DockTabViewModel } from "./dock-tabs.injectable";
|
||||||
import type { DockTab } from "../dock-tab";
|
|
||||||
import activeDockTabInjectable from "./active-dock-tab.injectable";
|
import activeDockTabInjectable from "./active-dock-tab.injectable";
|
||||||
|
|
||||||
const NonInjectedDockHost = observer(({ dockTabs, activeDockTab }: Dependencies) => {
|
const NonInjectedDockHost = observer(({ dockTabs, activeDockTab }: Dependencies) => {
|
||||||
const { ContentComponent: DockTabContent } = activeDockTab.get();
|
const {
|
||||||
|
type: { ContentComponent: DockTabContent },
|
||||||
|
} = activeDockTab.get();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Div>
|
<Div>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Map items={dockTabs.get()}>
|
<Map items={dockTabs.get()}>
|
||||||
{({ id, TitleComponent, activate }) => (
|
{({ id, type: { TitleComponent }, activate }) => (
|
||||||
<Tabs.Tab data-dock-tab-test={id} onClick={activate}>
|
<Tabs.Tab data-dock-tab-test={id} onClick={activate}>
|
||||||
<TitleComponent />
|
<TitleComponent />
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
@ -31,8 +32,8 @@ const NonInjectedDockHost = observer(({ dockTabs, activeDockTab }: Dependencies)
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
dockTabs: IComputedValue<ActivatableDockTab[]>;
|
dockTabs: IComputedValue<DockTabViewModel[]>;
|
||||||
activeDockTab: IComputedValue<DockTab>;
|
activeDockTab: IComputedValue<DockTabViewModel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DockHost = withInjectables<Dependencies>(
|
export const DockHost = withInjectables<Dependencies>(
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { observable } from "mobx";
|
||||||
|
|
||||||
|
export interface DockTabInState {
|
||||||
|
id: string;
|
||||||
|
typeId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dockTabStateInjectable = getInjectable({
|
||||||
|
id: "dock-tab-state",
|
||||||
|
instantiate: () => observable.set<DockTabInState>(),
|
||||||
|
});
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
|
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
|
||||||
import { dockTabInjectionToken } from "../dock-tab";
|
import { dockTabTypeInjectionToken } from "../dock-tab-type";
|
||||||
|
|
||||||
const dockTabTypesInjectable = getInjectable({
|
const dockTabTypesInjectable = getInjectable({
|
||||||
id: "dock-tab-types",
|
id: "dock-tab-types",
|
||||||
@ -8,7 +8,7 @@ const dockTabTypesInjectable = getInjectable({
|
|||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const computedInjectMany = di.inject(computedInjectManyInjectable);
|
const computedInjectMany = di.inject(computedInjectManyInjectable);
|
||||||
|
|
||||||
return computedInjectMany(dockTabInjectionToken);
|
return computedInjectMany(dockTabTypeInjectionToken);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +1,46 @@
|
|||||||
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { filter, map } from "lodash/fp";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import type { DockTab } from "../dock-tab";
|
import type { DockTabType } from "../dock-tab-type";
|
||||||
|
import { dockTabStateInjectable } from "./dock-tab-state.injectable";
|
||||||
import activateDockTabInjectable from "./activate-dock-tab.injectable";
|
import activateDockTabInjectable from "./activate-dock-tab.injectable";
|
||||||
import dockTabTypesInjectable from "./dock-tabs-types.injectable";
|
import dockTabTypesInjectable from "./dock-tabs-types.injectable";
|
||||||
|
|
||||||
type Activatable = { activate: () => void };
|
export interface DockTabViewModel {
|
||||||
|
id: string;
|
||||||
export type ActivatableDockTab = DockTab & Activatable;
|
type: DockTabType;
|
||||||
|
activate: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
const dockTabsInjectable = getInjectable({
|
const dockTabsInjectable = getInjectable({
|
||||||
id: "dock-tabs",
|
id: "dock-tabs",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const dockTabTypes = di.inject(dockTabTypesInjectable);
|
const dockTabTypes = di.inject(dockTabTypesInjectable);
|
||||||
const activateFor = di.injectFactory(activateDockTabInjectable);
|
const dockTabState = di.inject(dockTabStateInjectable);
|
||||||
|
const activateDockTab = di.inject(activateDockTabInjectable);
|
||||||
|
|
||||||
return computed(() =>
|
return computed((): DockTabViewModel[] => {
|
||||||
dockTabTypes.get().map((tab) => ({
|
const dereferencedDockTabTypes = dockTabTypes.get();
|
||||||
...tab,
|
|
||||||
|
|
||||||
activate: activateFor(tab.id),
|
return pipeline(
|
||||||
})),
|
[...dockTabState.values()],
|
||||||
);
|
|
||||||
|
map((tab) => ({
|
||||||
|
tab,
|
||||||
|
type: dereferencedDockTabTypes.find((type) => type.id === tab.typeId),
|
||||||
|
})),
|
||||||
|
|
||||||
|
filter(({ type }) => !!type),
|
||||||
|
|
||||||
|
map(({ tab, type }) => ({
|
||||||
|
id: tab.id,
|
||||||
|
type: type as DockTabType,
|
||||||
|
activate: () => activateDockTab(tab.id),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { v4 as getRandomId } from "uuid";
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
export type GetRandomId = () => string;
|
||||||
|
|
||||||
|
export const getRandomIdInjectionToken = getInjectionToken<GetRandomId>({
|
||||||
|
id: "get-random-id-injection-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
const getRandomIdInjectable = getInjectable({
|
||||||
|
id: "get-random-id",
|
||||||
|
instantiate: () => () => getRandomId(),
|
||||||
|
causesSideEffects: true,
|
||||||
|
injectionToken: getRandomIdInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getRandomIdInjectable;
|
||||||
Loading…
Reference in New Issue
Block a user