mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Show extension preferences in separate page (#5284)
Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
91ee7bd785
commit
0784085bf4
10
package.json
10
package.json
@ -208,11 +208,11 @@
|
||||
"@hapi/subtext": "^7.0.4",
|
||||
"@kubernetes/client-node": "^0.16.3",
|
||||
"@material-ui/styles": "^4.11.5",
|
||||
"@ogre-tools/fp": "8.0.0",
|
||||
"@ogre-tools/injectable": "8.0.0",
|
||||
"@ogre-tools/injectable-extension-for-auto-registration": "8.0.0",
|
||||
"@ogre-tools/injectable-extension-for-mobx": "8.0.0",
|
||||
"@ogre-tools/injectable-react": "8.0.0",
|
||||
"@ogre-tools/fp": "9.0.0",
|
||||
"@ogre-tools/injectable": "9.0.0",
|
||||
"@ogre-tools/injectable-extension-for-auto-registration": "9.0.0",
|
||||
"@ogre-tools/injectable-extension-for-mobx": "9.0.0",
|
||||
"@ogre-tools/injectable-react": "9.0.0",
|
||||
"@sentry/electron": "^3.0.7",
|
||||
"@sentry/integrations": "^6.19.3",
|
||||
"@side/jest-runtime": "^1.0.1",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -250,6 +250,7 @@ const testNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "some-test-preference-navigation-item-id",
|
||||
label: "Some preference navigation item",
|
||||
parent: "general",
|
||||
isActive: routeIsActive,
|
||||
isVisible: testRoute.isEnabled,
|
||||
navigate: navigateToPreferenceTab(testRoute),
|
||||
|
||||
@ -6,8 +6,13 @@ import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import React from "react";
|
||||
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import type { FakeExtensionData, TestExtension } from "../../renderer/components/test-utils/get-renderer-extension-fake";
|
||||
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting";
|
||||
import extensionPreferencesRouteInjectable from "../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
|
||||
|
||||
|
||||
describe("preferences - navigation to extension specific preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
@ -43,10 +48,65 @@ describe("preferences - navigation to extension specific preferences", () => {
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
describe("given multiple extensions with specific preferences, when navigating to extension specific preferences page", () => {
|
||||
beforeEach(async () => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
|
||||
const someOtherTestExtension = getRendererExtensionFake(someOtherExtensionStubWithExtensionSpecificPreferenceItems);
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(someTestExtension, someOtherTestExtension);
|
||||
applicationBuilder.preferences.navigation.click("extension-some-test-extension-id");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("doesn't show preferences from unrelated extension", () => {
|
||||
const actual = rendered.queryByTestId("extension-preference-item-for-some-other-preference-item-id");
|
||||
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
it("shows preferences from related extension", () => {
|
||||
const actual = rendered.getByTestId("extension-preference-item-for-some-preference-item-id");
|
||||
|
||||
expect(actual).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given multiple extensions with and without specific preferences", () => {
|
||||
beforeEach(async () => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
|
||||
const extensionWithoutPreferences = getRendererExtensionFake(extensionStubWithoutPreferences);
|
||||
const extensionWithSpecificTab = getRendererExtensionFake(extensionStubWithShowInPreferencesTab);
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(someTestExtension, extensionWithoutPreferences, extensionWithSpecificTab);
|
||||
});
|
||||
|
||||
it("doesn't show link for extension without preferences", () => {
|
||||
const actual = rendered.queryByTestId("tab-link-for-extension-without-preferences-id");
|
||||
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
it("doesn't show link for preferences intended for a specific tab", () => {
|
||||
const actual = rendered.queryByTestId("tab-link-for-extension-specified-preferences-page-id");
|
||||
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when extension with specific preferences is enabled", () => {
|
||||
let testExtension: TestExtension;
|
||||
|
||||
beforeEach(() => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const testExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
|
||||
|
||||
testExtension = getRendererExtensionFake(
|
||||
extensionStubWithExtensionSpecificPreferenceItems,
|
||||
);
|
||||
|
||||
applicationBuilder.extensions.renderer.enable(testExtension);
|
||||
});
|
||||
@ -56,20 +116,32 @@ describe("preferences - navigation to extension specific preferences", () => {
|
||||
});
|
||||
|
||||
it("shows link for extension preferences", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extensions");
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id");
|
||||
|
||||
expect(actual).not.toBeNull();
|
||||
});
|
||||
|
||||
it("link should not be active", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id");
|
||||
|
||||
expect(actual).not.toHaveClass("active");
|
||||
});
|
||||
|
||||
describe("when navigating to extension preferences using navigation", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.preferences.navigation.click("extensions");
|
||||
applicationBuilder.preferences.navigation.click("extension-some-test-extension-id");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows proper page title", () => {
|
||||
const title = rendered.getByText("some-test-extension-id preferences");
|
||||
|
||||
expect(title).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows extension specific preferences", () => {
|
||||
const page = rendered.getByTestId("extension-preferences-page");
|
||||
|
||||
@ -87,14 +159,234 @@ describe("preferences - navigation to extension specific preferences", () => {
|
||||
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
it("link is active", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id");
|
||||
|
||||
expect(actual).toHaveClass("active");
|
||||
});
|
||||
|
||||
describe("when extension is disabled", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.extensions.renderer.disable(testExtension);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the error message about extension not being present", () => {
|
||||
expect(rendered.getByTestId("error-for-extension-not-being-present")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when extension is enabled again, does not show the error message anymore", () => {
|
||||
applicationBuilder.extensions.renderer.enable(testExtension);
|
||||
|
||||
expect(rendered.queryByTestId("error-for-extension-not-being-present")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension with registered tab", () => {
|
||||
beforeEach(async () => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(extension);
|
||||
});
|
||||
|
||||
it("shows extension tab in general area", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-registered-tab-page-id-nav-item-metrics-extension-tab");
|
||||
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show custom settings block", () => {
|
||||
const actual = rendered.queryByTestId("extension-settings");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when navigating to specific extension tab", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab");
|
||||
});
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
it("shows related preferences for this tab", () => {
|
||||
const actual = rendered.getByTestId("metrics-preference-item-hint");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
it("does not show unrelated preferences for this tab", () => {
|
||||
const actual = rendered.queryByTestId("survey-preference-item-hint");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension with few registered tabs", () => {
|
||||
const tabs = [
|
||||
"tab-link-for-extension-hello-world-tab-page-id-nav-item-hello-extension-tab",
|
||||
"tab-link-for-extension-hello-world-tab-page-id-nav-item-logs-extension-tab",
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTabs);
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(extension);
|
||||
});
|
||||
|
||||
it.each(tabs)("shows '%s' tab in general area", (tab) => {
|
||||
const tabElement = rendered.getByTestId(tab);
|
||||
|
||||
expect(tabElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extensions with tabs having same id", () => {
|
||||
beforeEach(async () => {
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
|
||||
const otherExtension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(extension, otherExtension);
|
||||
});
|
||||
|
||||
it("shows tab from the first extension", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-registered-tab-page-id-nav-item-metrics-extension-tab");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows tab from the second extension", () => {
|
||||
const actual = rendered.getByTestId("tab-link-for-extension-duplicated-tab-page-id-nav-item-metrics-extension-tab");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when navigating to first extension tab", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows related preferences for this tab", () => {
|
||||
const actual = rendered.getByTestId("metrics-preference-item-hint");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show unrelated preferences for this tab", () => {
|
||||
const actual = rendered.queryByTestId("another-metrics-preference-item-hint");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when navigating to second extension tab", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.preferences.navigation.click("extension-duplicated-tab-page-id-nav-item-metrics-extension-tab");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows related preferences for this tab", () => {
|
||||
const actual = rendered.getByTestId("another-metrics-preference-item-hint");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show unrelated preferences for this tab", () => {
|
||||
const actual = rendered.queryByTestId("metrics-preference-item-hint");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when navigating to extension specific tab", () => {
|
||||
let rendered: RenderResult;
|
||||
let di: DiContainer;
|
||||
|
||||
beforeEach(async () => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const extension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
|
||||
const otherExtension = getRendererExtensionFake(extensionUsingSomeoneElseTab);
|
||||
|
||||
applicationBuilder.beforeRender(() => {
|
||||
const extensionRoute = di.inject(extensionPreferencesRouteInjectable);
|
||||
const params = { parameters: {
|
||||
extensionId: "duplicated-tab-page-id",
|
||||
tabId: "metrics-extension-tab",
|
||||
}};
|
||||
|
||||
applicationBuilder.preferences.navigateTo(extensionRoute, params);
|
||||
});
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(extension, otherExtension);
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does render related preferences for specific tab", () => {
|
||||
expect(rendered.getByTestId("another-metrics-preference-item-hint")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not render related preferences for specific tab", () => {
|
||||
expect(rendered.queryByTestId("my-preferences-item-hint")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when navigating to someone else extension specific tab", () => {
|
||||
let rendered: RenderResult;
|
||||
let di: DiContainer;
|
||||
|
||||
beforeEach(async () => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
|
||||
const extension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
|
||||
const extensionUsingOtherTab = getRendererExtensionFake(extensionUsingSomeoneElseTab);
|
||||
|
||||
applicationBuilder.beforeRender(() => {
|
||||
const extensionRoute = di.inject(extensionPreferencesRouteInjectable);
|
||||
const params = { parameters: {
|
||||
extensionId: "extension-using-someone-else-tab-id",
|
||||
tabId: "metrics-extension-tab",
|
||||
}};
|
||||
|
||||
applicationBuilder.preferences.navigateTo(extensionRoute, params);
|
||||
});
|
||||
|
||||
await applicationBuilder.extensions.renderer.enable(extension, extensionUsingOtherTab);
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = {
|
||||
id: "some-extension-id",
|
||||
name: "some-extension-name",
|
||||
id: "some-test-extension-id",
|
||||
name: "some-test-extension-id",
|
||||
appPreferences: [
|
||||
{
|
||||
title: "Some preference item",
|
||||
@ -119,3 +411,166 @@ const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = {
|
||||
],
|
||||
};
|
||||
|
||||
const someOtherExtensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = {
|
||||
id: "some-other-test-extension-id",
|
||||
name: "some-other-test-extension-id",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "Test preference item",
|
||||
id: "some-other-preference-item-id",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="some-other-preference-item-hint" />,
|
||||
Input: () => <div data-testid="some-other-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const extensionStubWithoutPreferences: FakeExtensionData = {
|
||||
id: "without-preferences-id",
|
||||
name: "without-preferences-id",
|
||||
};
|
||||
|
||||
const extensionStubWithShowInPreferencesTab: FakeExtensionData = {
|
||||
id: "specified-preferences-page-id",
|
||||
name: "specified-preferences-page-name",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "Test preference item",
|
||||
id: "very-other-preference-item-id",
|
||||
showInPreferencesTab: "some-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="very-other-preference-item-hint" />,
|
||||
Input: () => <div data-testid="very-other-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const extensionStubWithWithRegisteredTab: FakeExtensionData = {
|
||||
id: "registered-tab-page-id",
|
||||
name: "registered-tab-page-id",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "License item",
|
||||
id: "metrics-preference-item-id",
|
||||
showInPreferencesTab: "metrics-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="metrics-preference-item-hint" />,
|
||||
Input: () => <div data-testid="metrics-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Menu item",
|
||||
id: "menu-preference-item-id",
|
||||
showInPreferencesTab: "menu-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="menu-preference-item-hint" />,
|
||||
Input: () => <div data-testid="menu-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Survey item",
|
||||
id: "survey-preference-item-id",
|
||||
showInPreferencesTab: "survey-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="survey-preference-item-hint" />,
|
||||
Input: () => <div data-testid="survey-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
appPreferenceTabs: [{
|
||||
title: "Metrics tab",
|
||||
id: "metrics-extension-tab",
|
||||
orderNumber: 100,
|
||||
}],
|
||||
};
|
||||
|
||||
const extensionStubWithWithRegisteredTabs: FakeExtensionData = {
|
||||
id: "hello-world-tab-page-id",
|
||||
name: "hello-world-tab-page-id",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "Hello world",
|
||||
id: "hello-preference-item-id",
|
||||
showInPreferencesTab: "hello-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="hello-preference-item-hint" />,
|
||||
Input: () => <div data-testid="hello-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Logs",
|
||||
id: "logs-preference-item-id",
|
||||
showInPreferencesTab: "logs-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="logs-preference-item-hint" />,
|
||||
Input: () => <div data-testid="logs-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
appPreferenceTabs: [{
|
||||
title: "Metrics tab",
|
||||
id: "hello-extension-tab",
|
||||
orderNumber: 100,
|
||||
}, {
|
||||
title: "Logs tab",
|
||||
id: "logs-extension-tab",
|
||||
orderNumber: 200,
|
||||
}],
|
||||
};
|
||||
|
||||
const extensionStubWithWithSameRegisteredTab: FakeExtensionData = {
|
||||
id: "duplicated-tab-page-id",
|
||||
name: "duplicated-tab-page-id",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "Another metrics",
|
||||
id: "another-metrics-preference-item-id",
|
||||
showInPreferencesTab: "metrics-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="another-metrics-preference-item-hint" />,
|
||||
Input: () => <div data-testid="another-metrics-preference-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
appPreferenceTabs: [{
|
||||
title: "Metrics tab",
|
||||
id: "metrics-extension-tab",
|
||||
orderNumber: 100,
|
||||
}],
|
||||
};
|
||||
|
||||
const extensionUsingSomeoneElseTab: FakeExtensionData = {
|
||||
id: "extension-using-someone-else-tab-id",
|
||||
name: "extension-using-someone-else-tab-id",
|
||||
|
||||
appPreferences: [
|
||||
{
|
||||
title: "My preferences",
|
||||
id: "my-preferences-item-id",
|
||||
showInPreferencesTab: "metrics-extension-tab",
|
||||
|
||||
components: {
|
||||
Hint: () => <div data-testid="my-preferences-item-hint" />,
|
||||
Input: () => <div data-testid="my-preferences-item-input" />,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@ -5,12 +5,18 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token";
|
||||
import type { Route } from "../../../front-end-route-injection-token";
|
||||
|
||||
interface ExtensionPreferenceRouteParams {
|
||||
extensionId: string;
|
||||
tabId?: string;
|
||||
}
|
||||
|
||||
const extensionPreferencesRouteInjectable = getInjectable({
|
||||
id: "extension-preferences-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/preferences/extensions",
|
||||
instantiate: (): Route<ExtensionPreferenceRouteParams> => ({
|
||||
path: "/preferences/extension/:extensionId/:tabId?",
|
||||
clusterFrame: false,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
@ -13,7 +13,10 @@ const navigateToExtensionPreferencesInjectable = getInjectable({
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
const route = di.inject(extensionPreferencesRouteInjectable);
|
||||
|
||||
return () => navigateToRoute(route);
|
||||
return (extensionId: string, tabId?: string) => navigateToRoute(route, { parameters: {
|
||||
extensionId,
|
||||
tabId,
|
||||
}});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ describe("runManyFor", () => {
|
||||
let actualPromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
runMock = asyncFn();
|
||||
|
||||
@ -67,7 +67,7 @@ describe("runManyFor", () => {
|
||||
let actualPromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = createContainer();
|
||||
const di = createContainer("irrelevant");
|
||||
|
||||
runMock = asyncFn();
|
||||
|
||||
@ -170,7 +170,7 @@ describe("runManyFor", () => {
|
||||
});
|
||||
|
||||
it("given invalid hierarchy, when running runnables, throws", () => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
const runMock = asyncFn<(...args: unknown[]) => void>();
|
||||
|
||||
@ -218,7 +218,7 @@ describe("runManyFor", () => {
|
||||
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
runMock = asyncFn();
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ describe("runManySyncFor", () => {
|
||||
let runMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
runMock = jest.fn();
|
||||
|
||||
@ -50,7 +50,7 @@ describe("runManySyncFor", () => {
|
||||
let runMock: jest.Mock<(arg: string) => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = createContainer();
|
||||
const di = createContainer("irrelevant");
|
||||
|
||||
runMock = jest.fn();
|
||||
|
||||
@ -99,7 +99,7 @@ describe("runManySyncFor", () => {
|
||||
});
|
||||
|
||||
it("given invalid hierarchy, when running runnables, throws", () => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
const runMock = jest.fn();
|
||||
|
||||
@ -147,7 +147,7 @@ describe("runManySyncFor", () => {
|
||||
let runMock: jest.Mock<(arg: string, arg2: string) => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer();
|
||||
const rootDi = createContainer("irrelevant");
|
||||
|
||||
runMock = jest.fn();
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ describe("asLegacyGlobalObjectForExtensionApiWithModifications", () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
di = createContainer();
|
||||
di = createContainer("irrelevant");
|
||||
|
||||
jest.spyOn(di, "inject");
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ import { pipeline } from "@ogre-tools/fp";
|
||||
import { getExtensionRoutePath } from "../renderer/routes/for-extension";
|
||||
import type { LensRendererExtensionDependencies } from "./lens-extension-set-dependencies";
|
||||
import type { KubeObjectHandlerRegistration } from "../renderer/kube-object/handler";
|
||||
import type { AppPreferenceTabRegistration } from "../renderer/components/+preferences/app-preference-tab/app-preference-tab-registration";
|
||||
|
||||
export class LensRendererExtension extends LensExtension<LensRendererExtensionDependencies> {
|
||||
globalPages: registries.PageRegistration[] = [];
|
||||
@ -33,6 +34,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
||||
clusterPageMenus: registries.ClusterPageMenuRegistration[] = [];
|
||||
kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [];
|
||||
appPreferences: AppPreferenceRegistration[] = [];
|
||||
appPreferenceTabs: AppPreferenceTabRegistration[] = [];
|
||||
entitySettings: registries.EntitySettingRegistration[] = [];
|
||||
statusBarItems: StatusBarRegistration[] = [];
|
||||
kubeObjectDetailItems: registries.KubeObjectDetailRegistration[] = [];
|
||||
|
||||
@ -8,7 +8,7 @@ import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
|
||||
export const getDi = () => {
|
||||
const di = createContainer();
|
||||
const di = createContainer("main");
|
||||
|
||||
registerMobX(di);
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
doGeneralOverrides = false,
|
||||
} = opts;
|
||||
|
||||
const di = createContainer();
|
||||
const di = createContainer("main");
|
||||
|
||||
registerMobX(di);
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface AppPreferenceTabRegistration {
|
||||
title: string;
|
||||
id: string;
|
||||
orderNumber?: number;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import { filter, map } from "lodash/fp";
|
||||
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { extensionPreferenceItemInjectionToken } from "./extension-preference-items.injectable";
|
||||
import { extensionPreferenceItemInjectionToken } from "./extension-preference-items-injection-token";
|
||||
|
||||
const extensionPreferenceItemRegistratorInjectable = getInjectable({
|
||||
id: "extension-preference-item-registrator",
|
||||
@ -34,6 +34,7 @@ const extensionPreferenceItemRegistratorInjectable = getInjectable({
|
||||
instantiate: () => ({
|
||||
id: registration.id || id,
|
||||
title: registration.title,
|
||||
extension,
|
||||
|
||||
components: {
|
||||
Hint: registration.components.Hint,
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||
import type { RegisteredAppPreference } from "./app-preferences/app-preference-registration";
|
||||
|
||||
interface ExtensionPreferenceItem extends RegisteredAppPreference {
|
||||
extension: LensRendererExtension;
|
||||
}
|
||||
|
||||
export const extensionPreferenceItemInjectionToken = getInjectionToken<ExtensionPreferenceItem>({
|
||||
id: "extension-preference-item-injection-token",
|
||||
});
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import extensionPreferencesRouteInjectable from "../../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
|
||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||
import routePathParametersInjectable from "../../routes/route-path-parameters.injectable";
|
||||
import { getExtensionPreferenceItems } from "./get-extension-preference-items";
|
||||
|
||||
const extensionPreferencesModelInjectable = getInjectable({
|
||||
id: "extension-preferences-model",
|
||||
|
||||
instantiate: (di) => {
|
||||
const route = di.inject(extensionPreferencesRouteInjectable);
|
||||
const pathParameters = di.inject(routePathParametersInjectable, route);
|
||||
const extensions = di.inject(rendererExtensionsInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const { extensionId, tabId } = pathParameters.get();
|
||||
const targetExtension = extensions.get().find((extension) => extension.sanitizedExtensionId === extensionId);
|
||||
|
||||
return {
|
||||
extensionName: targetExtension?.manifest.name,
|
||||
preferenceItems: getExtensionPreferenceItems(targetExtension, tabId),
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default extensionPreferencesModelInjectable;
|
||||
@ -8,36 +8,55 @@ import type { IComputedValue } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import type { RegisteredAppPreference } from "./app-preferences/app-preference-registration";
|
||||
import extensionPreferencesModelInjectable from "./extension-preference-model.injectable";
|
||||
import { ExtensionSettings } from "./extension-settings";
|
||||
import { Preferences } from "./preferences";
|
||||
import extensionsPreferenceItemsInjectable from "./extension-preference-items.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
preferenceItems: IComputedValue<RegisteredAppPreference[]>;
|
||||
model: IComputedValue<{
|
||||
preferenceItems: RegisteredAppPreference[];
|
||||
extensionName?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
const NonInjectedExtensions = ({ preferenceItems }: Dependencies) => (
|
||||
<Preferences data-testid="extension-preferences-page">
|
||||
<section id="extensions">
|
||||
<h2>Extensions</h2>
|
||||
{preferenceItems.get().map((preferenceItem) => (
|
||||
<ExtensionSettings
|
||||
key={preferenceItem.id}
|
||||
setting={preferenceItem}
|
||||
size="small"
|
||||
data-testid={`extension-preference-item-for-${preferenceItem.id}`}
|
||||
/>
|
||||
))}
|
||||
</section>
|
||||
</Preferences>
|
||||
);
|
||||
const NonInjectedExtensions = ({ model }: Dependencies) => {
|
||||
const { extensionName, preferenceItems } = model.get();
|
||||
|
||||
return (
|
||||
<Preferences data-testid="extension-preferences-page">
|
||||
<section id="extensions">
|
||||
<h2>
|
||||
{extensionName}
|
||||
{" "}
|
||||
preferences
|
||||
</h2>
|
||||
{!extensionName && (
|
||||
<div
|
||||
className="flex items-center"
|
||||
data-testid="error-for-extension-not-being-present"
|
||||
>
|
||||
No extension found
|
||||
</div>
|
||||
)}
|
||||
{preferenceItems.map((preferenceItem, index) => (
|
||||
<ExtensionSettings
|
||||
key={`${preferenceItem.id}-${index}`}
|
||||
setting={preferenceItem}
|
||||
size="small"
|
||||
data-testid={`extension-preference-item-for-${preferenceItem.id}`}
|
||||
/>
|
||||
))}
|
||||
</section>
|
||||
</Preferences>
|
||||
);
|
||||
};
|
||||
|
||||
export const Extensions = withInjectables<Dependencies>(
|
||||
observer(NonInjectedExtensions),
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
preferenceItems: di.inject(extensionsPreferenceItemsInjectable),
|
||||
model: di.inject(extensionPreferencesModelInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||
import type { RegisteredAppPreference } from "./app-preferences/app-preference-registration";
|
||||
|
||||
export function getExtensionPreferenceItems(extension?: LensRendererExtension, tabId?: string): RegisteredAppPreference[] {
|
||||
if (!extension) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const preferences = extension.appPreferences.map(preference => ({
|
||||
id: preference.id || preference.title,
|
||||
...preference,
|
||||
}));
|
||||
|
||||
if (tabId) {
|
||||
return preferences.filter(preference => preference.showInPreferencesTab == tabId);
|
||||
}
|
||||
|
||||
return preferences.filter(preference => !preference.showInPreferencesTab);
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { computed } from "mobx";
|
||||
import { noop } from "../../../../utils";
|
||||
import type { ApplicationBuilder } from "../../../test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../test-utils/get-application-builder";
|
||||
import type { PreferenceNavigationItem } from "../preference-navigation-items.injectable";
|
||||
import preferenceNavigationItemsInjectable from "../preference-navigation-items.injectable";
|
||||
|
||||
describe.only("preferences - navigation block with links", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
});
|
||||
|
||||
describe("given in preferences, when rendered", () => {
|
||||
let renderer: RenderResult;
|
||||
|
||||
describe("when general navigation items passed", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(preferenceNavigationItemsInjectable, () =>
|
||||
computed(() => generalNavItems),
|
||||
);
|
||||
});
|
||||
|
||||
applicationBuilder.beforeRender(() => {
|
||||
applicationBuilder.preferences.navigate();
|
||||
});
|
||||
|
||||
renderer = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
const links = ["General", "Proxy"];
|
||||
|
||||
it.each(links)("renders link with text content %s", (link) => {
|
||||
expect(renderer.container).toHaveTextContent(link);
|
||||
});
|
||||
|
||||
it("does not show custom settings block", () => {
|
||||
expect(
|
||||
renderer.queryByTestId("extension-settings"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when general + extension navigation items passed", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(preferenceNavigationItemsInjectable, () =>
|
||||
computed(() => [...generalNavItems, ...extensionNavItems]),
|
||||
);
|
||||
});
|
||||
|
||||
applicationBuilder.beforeRender(() => {
|
||||
applicationBuilder.preferences.navigate();
|
||||
});
|
||||
|
||||
renderer = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
const generalLinks = ["General", "Proxy"];
|
||||
|
||||
it.each(generalLinks)(
|
||||
"renders general link with text content %s",
|
||||
(link) => {
|
||||
expect(renderer.container).toHaveTextContent(link);
|
||||
},
|
||||
);
|
||||
|
||||
it("shows custom settings block", () => {
|
||||
expect(
|
||||
renderer.queryByTestId("extension-settings"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const extensionLinks = ["lensapp-node-menu", "lensapp-pod-menu"];
|
||||
|
||||
it.each(extensionLinks)("shows extension navigation item %s", (link) => {
|
||||
expect(
|
||||
renderer.getByTestId(
|
||||
`tab-link-for-extension-preferences-navigation-item-${link}`,
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders extension navigation items inside custom settings block", () => {
|
||||
const settingsBlock = renderer.getByTestId("extension-settings");
|
||||
|
||||
expect(settingsBlock).toHaveTextContent("lensapp-node-menu");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const generalNavItems: PreferenceNavigationItem[] = [
|
||||
{
|
||||
id: "general",
|
||||
label: "General",
|
||||
isActive: computed(() => false),
|
||||
isVisible: computed(() => true),
|
||||
navigate: () => noop,
|
||||
orderNumber: 0,
|
||||
parent: "general",
|
||||
},
|
||||
{
|
||||
id: "proxy",
|
||||
label: "Proxy",
|
||||
isActive: computed(() => false),
|
||||
isVisible: computed(() => true),
|
||||
navigate: () => noop,
|
||||
orderNumber: 1,
|
||||
parent: "general",
|
||||
},
|
||||
];
|
||||
|
||||
const extensionNavItems = [
|
||||
{
|
||||
id: "extension-preferences-navigation-item-lensapp-node-menu",
|
||||
label: "lensapp-node-menu",
|
||||
isActive: computed(() => false),
|
||||
isVisible: computed(() => true),
|
||||
navigate: () => noop,
|
||||
orderNumber: 0,
|
||||
parent: "extensions",
|
||||
},
|
||||
{
|
||||
id: "extension-preferences-navigation-item-lensapp-pod-menu",
|
||||
label: "lensapp-pod-menu",
|
||||
isActive: computed(() => false),
|
||||
isVisible: computed(() => true),
|
||||
navigate: () => noop,
|
||||
orderNumber: 0,
|
||||
parent: "extensions",
|
||||
},
|
||||
{
|
||||
id: "extension-preferences-navigation-item-metrics-plugin",
|
||||
label: "metrics-plugin",
|
||||
isActive: computed(() => false),
|
||||
isVisible: computed(() => false),
|
||||
navigate: () => noop,
|
||||
orderNumber: 0,
|
||||
parent: "extensions",
|
||||
},
|
||||
];
|
||||
|
||||
@ -24,6 +24,7 @@ const applicationPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "application",
|
||||
label: "App",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
isVisible: computed(() => true),
|
||||
|
||||
@ -24,6 +24,7 @@ const editorPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "editor",
|
||||
label: "Editor",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
isVisible: computed(() => true),
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import { map } from "lodash/fp";
|
||||
|
||||
import routeIsActiveInjectable from "../../../routes/route-is-active.injectable";
|
||||
import { preferenceNavigationItemInjectionToken } from "./preference-navigation-items.injectable";
|
||||
|
||||
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import extensionPreferencesRouteInjectable from "../../../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
|
||||
import navigateToExtensionPreferencesInjectable from "../../../../common/front-end-routing/routes/preferences/extension/navigate-to-extension-preferences.injectable";
|
||||
import type { LensExtension } from "../../../../extensions/lens-extension";
|
||||
import routePathParametersInjectable from "../../../routes/route-path-parameters.injectable";
|
||||
|
||||
const extensionSpecificTabNavigationItemRegistratorInjectable = getInjectable({
|
||||
id: "extension-specific-tab-preferences-navigation-items",
|
||||
|
||||
instantiate: (di) => {
|
||||
return (ext: LensExtension) => {
|
||||
const extension = ext as LensRendererExtension;
|
||||
const navigateToExtensionPreferences = di.inject(
|
||||
navigateToExtensionPreferencesInjectable,
|
||||
);
|
||||
const route = di.inject(extensionPreferencesRouteInjectable);
|
||||
const routeIsActive = di.inject(routeIsActiveInjectable, route);
|
||||
const pathParameters = di.inject(routePathParametersInjectable, route);
|
||||
|
||||
return pipeline(
|
||||
extension.appPreferenceTabs,
|
||||
|
||||
map((tab) => {
|
||||
const id = `extension-${extension.sanitizedExtensionId}-nav-item-${tab.id}`;
|
||||
const isActive = computed(() => routeIsActive.get() && pathParameters.get().tabId === tab.id);
|
||||
|
||||
return getInjectable({
|
||||
id,
|
||||
injectionToken: preferenceNavigationItemInjectionToken,
|
||||
instantiate: () => ({
|
||||
id,
|
||||
label: tab.title,
|
||||
parent: "general",
|
||||
orderNumber: tab.orderNumber || 100,
|
||||
navigate: () => navigateToExtensionPreferences(extension.sanitizedExtensionId, tab.id),
|
||||
isVisible: computed(() => true),
|
||||
isActive,
|
||||
}),
|
||||
});
|
||||
}),
|
||||
);
|
||||
};
|
||||
},
|
||||
injectionToken: extensionRegistratorInjectionToken,
|
||||
});
|
||||
|
||||
export default extensionSpecificTabNavigationItemRegistratorInjectable;
|
||||
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import type { PreferenceNavigationItem } from "./preference-navigation-items.injectable";
|
||||
import { Icon } from "../../icon";
|
||||
import { PreferencesNavigationTab } from "./preference-navigation-tab";
|
||||
import preferenceNavigationItemsForGroupInjectable from "./preference-navigation-items-for-group.injectable";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
interface Dependencies {
|
||||
navigationItems: IComputedValue<PreferenceNavigationItem[]>;
|
||||
}
|
||||
|
||||
const NonInjectedExtensionsNavGroup = observer((props: Dependencies) => {
|
||||
if (!props.navigationItems.get().length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div data-testid="extension-settings">
|
||||
<hr/>
|
||||
<div className="header flex items-center">
|
||||
<Icon
|
||||
material="extension"
|
||||
smallest
|
||||
className="mr-3"
|
||||
/>
|
||||
{" "}
|
||||
Extensions
|
||||
</div>
|
||||
<div>
|
||||
{props.navigationItems.get().map(item => (
|
||||
<PreferencesNavigationTab
|
||||
key={item.id}
|
||||
item={item}
|
||||
data-testid={`tab-link-for-${item.id}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const ExtensionsNavGroup = withInjectables<Dependencies>(
|
||||
NonInjectedExtensionsNavGroup,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
navigationItems: di.inject(preferenceNavigationItemsForGroupInjectable, "extensions"),
|
||||
}),
|
||||
},
|
||||
);
|
||||
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import extensionPreferencesRouteInjectable from "../../../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
|
||||
import navigateToExtensionPreferencesInjectable from "../../../../common/front-end-routing/routes/preferences/extension/navigate-to-extension-preferences.injectable";
|
||||
import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import routeIsActiveInjectable from "../../../routes/route-is-active.injectable";
|
||||
import routePathParametersInjectable from "../../../routes/route-path-parameters.injectable";
|
||||
import { preferenceNavigationItemInjectionToken } from "./preference-navigation-items.injectable";
|
||||
|
||||
const extensionPreferencesNavigationItemRegistratorInjectable = getInjectable({
|
||||
id: "extension-preferences-navigation-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
return (ext) => {
|
||||
const extension = ext as LensRendererExtension;
|
||||
const navigateToExtensionPreferences = di.inject(
|
||||
navigateToExtensionPreferencesInjectable,
|
||||
);
|
||||
|
||||
const extensionHasPreferences = extension.appPreferences.length > 0;
|
||||
const extensionHasGeneralPreferences = extension.appPreferences.some(preferences =>
|
||||
!preferences.showInPreferencesTab,
|
||||
);
|
||||
const isVisible = computed(() => extensionHasPreferences && extensionHasGeneralPreferences);
|
||||
const extensionRoute = di.inject(extensionPreferencesRouteInjectable);
|
||||
const pathParameters = di.inject(routePathParametersInjectable, extensionRoute);
|
||||
const routeIsActive = di.inject(routeIsActiveInjectable, extensionRoute);
|
||||
const isActive = computed(() => routeIsActive.get() && pathParameters.get().extensionId === extension.sanitizedExtensionId);
|
||||
const id = `extension-preferences-navigation-item-${extension.sanitizedExtensionId}`;
|
||||
|
||||
const injectable = getInjectable({
|
||||
id,
|
||||
injectionToken: preferenceNavigationItemInjectionToken,
|
||||
instantiate: () => ({
|
||||
id: `extension-${extension.sanitizedExtensionId}`,
|
||||
label: `${extension.name}`,
|
||||
navigate: () => navigateToExtensionPreferences(extension.sanitizedExtensionId),
|
||||
isActive,
|
||||
isVisible,
|
||||
orderNumber: 20,
|
||||
parent: "extensions",
|
||||
}),
|
||||
});
|
||||
|
||||
return [injectable];
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: extensionRegistratorInjectionToken,
|
||||
});
|
||||
|
||||
export default extensionPreferencesNavigationItemRegistratorInjectable;
|
||||
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { preferenceNavigationItemInjectionToken } from "./preference-navigation-items.injectable";
|
||||
import routeIsActiveInjectable from "../../../routes/route-is-active.injectable";
|
||||
import { computed } from "mobx";
|
||||
import extensionsPreferenceItemsInjectable from "../extension-preference-items.injectable";
|
||||
import extensionPreferencesRouteInjectable from "../../../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
|
||||
import navigateToPreferenceTabInjectable from "./navigate-to-preference-tab.injectable";
|
||||
|
||||
const extensionsPreferencesNavigationItemInjectable = getInjectable({
|
||||
id: "extension-preferences-navigation-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const preferenceItems = di.inject(
|
||||
extensionsPreferenceItemsInjectable,
|
||||
);
|
||||
|
||||
const navigateToPreferenceTab = di.inject(
|
||||
navigateToPreferenceTabInjectable,
|
||||
);
|
||||
|
||||
const route = di.inject(
|
||||
extensionPreferencesRouteInjectable,
|
||||
);
|
||||
|
||||
const routeIsActive = di.inject(
|
||||
routeIsActiveInjectable,
|
||||
route,
|
||||
);
|
||||
|
||||
return {
|
||||
id: "extensions",
|
||||
label: "Extensions",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
|
||||
isVisible: computed(
|
||||
() => preferenceItems.get().length > 0,
|
||||
),
|
||||
|
||||
orderNumber: 70,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: preferenceNavigationItemInjectionToken,
|
||||
});
|
||||
|
||||
export default extensionsPreferencesNavigationItemInjectable;
|
||||
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import type { PreferenceNavigationItem } from "./preference-navigation-items.injectable";
|
||||
import { PreferencesNavigationTab } from "./preference-navigation-tab";
|
||||
import preferenceNavigationItemsForGroupInjectable from "./preference-navigation-items-for-group.injectable";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
interface Dependencies {
|
||||
navigationItems: IComputedValue<PreferenceNavigationItem[]>;
|
||||
}
|
||||
|
||||
const NonInjectedGeneralNavGroup = observer((props: Dependencies) => {
|
||||
if (!props.navigationItems.get().length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="header">Preferences</div>
|
||||
|
||||
{props.navigationItems.get().map(item => (
|
||||
<PreferencesNavigationTab
|
||||
key={item.id}
|
||||
item={item}
|
||||
data-testid={`tab-link-for-${item.id}`}
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
);
|
||||
});
|
||||
|
||||
export const GeneralNavGroup = withInjectables<Dependencies>(
|
||||
NonInjectedGeneralNavGroup,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
navigationItems: di.inject(preferenceNavigationItemsForGroupInjectable, "general"),
|
||||
}),
|
||||
},
|
||||
);
|
||||
@ -27,6 +27,7 @@ const kubernetesPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "kubernetes",
|
||||
label: "Kubernetes",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
isVisible: computed(() => true),
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import {
|
||||
getInjectable,
|
||||
lifecycleEnum,
|
||||
} from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import type { PreferenceNavigationItem } from "./preference-navigation-items.injectable";
|
||||
import preferenceNavigationItemsInjectable from "./preference-navigation-items.injectable";
|
||||
|
||||
const preferenceNavigationItemsForGroupInjectable = getInjectable({
|
||||
id: "preference-navigation-items-for-group",
|
||||
|
||||
instantiate: (di, group: string) => {
|
||||
const preferenceNavigationItems = di.inject(preferenceNavigationItemsInjectable);
|
||||
|
||||
return computed((): PreferenceNavigationItem[] =>
|
||||
preferenceNavigationItems.get().filter((item) => item.parent == group),
|
||||
);
|
||||
},
|
||||
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, group: string) => group,
|
||||
}),
|
||||
});
|
||||
|
||||
export default preferenceNavigationItemsForGroupInjectable;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import { filter, orderBy } from "lodash/fp";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { computed } from "mobx";
|
||||
@ -20,19 +21,24 @@ export interface PreferenceNavigationItem {
|
||||
isVisible: IComputedValue<boolean>;
|
||||
navigate: () => void;
|
||||
orderNumber: number;
|
||||
parent: string;
|
||||
}
|
||||
|
||||
const preferenceNavigationItemsInjectable = getInjectable({
|
||||
id: "preference-navigation-items",
|
||||
|
||||
instantiate: (di) =>
|
||||
computed((): PreferenceNavigationItem[] =>
|
||||
instantiate: (di) => {
|
||||
const computedInjectMany = di.inject(computedInjectManyInjectable);
|
||||
const navigationItems = computedInjectMany(preferenceNavigationItemInjectionToken);
|
||||
|
||||
return computed((): PreferenceNavigationItem[] =>
|
||||
pipeline(
|
||||
di.injectMany(preferenceNavigationItemInjectionToken),
|
||||
navigationItems.get(),
|
||||
filter((item) => !!item.isVisible.get()),
|
||||
(items) => orderBy([(item) => item.orderNumber], ["asc"], items),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default preferenceNavigationItemsInjectable;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import { Tab } from "../../tabs";
|
||||
import type { PreferenceNavigationItem } from "./preference-navigation-items.injectable";
|
||||
|
||||
interface PreferenceNavigationTabProps extends React.DOMAttributes<HTMLElement> {
|
||||
item: PreferenceNavigationItem;
|
||||
}
|
||||
|
||||
export const PreferencesNavigationTab = observer(({ item }: PreferenceNavigationTabProps) => (
|
||||
<Tab
|
||||
value={item}
|
||||
label={item.label}
|
||||
data-testid={`tab-link-for-${item.id}`}
|
||||
active={item.isActive.get()}
|
||||
/>
|
||||
));
|
||||
@ -2,61 +2,23 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { Tab, Tabs } from "../../tabs";
|
||||
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import React from "react";
|
||||
import { Tabs } from "../../tabs";
|
||||
import { ExtensionsNavGroup } from "./extensions-nav-group";
|
||||
import { GeneralNavGroup } from "./general-nav-group";
|
||||
import type {
|
||||
PreferenceNavigationItem,
|
||||
} from "./preference-navigation-items.injectable";
|
||||
import preferenceNavigationItemsInjectable from "./preference-navigation-items.injectable";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
interface Dependencies {
|
||||
navigationItems: IComputedValue<PreferenceNavigationItem[]>;
|
||||
}
|
||||
|
||||
const NonInjectedPreferencesNavigation = ({
|
||||
navigationItems,
|
||||
}: Dependencies) => (
|
||||
<Tabs
|
||||
className="flex column"
|
||||
scrollable={false}
|
||||
onChange={(item: PreferenceNavigationItem) => item.navigate()}
|
||||
>
|
||||
<div className="header">Preferences</div>
|
||||
|
||||
{navigationItems.get().map((item) => (
|
||||
<PreferencesNavigationTab
|
||||
key={item.id}
|
||||
item={item}
|
||||
data-testid={`tab-link-for-${item.id}`}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
interface PreferenceNavigationTabProps extends React.DOMAttributes<HTMLElement> {
|
||||
item: PreferenceNavigationItem;
|
||||
}
|
||||
|
||||
const PreferencesNavigationTab = observer(({ item }: PreferenceNavigationTabProps) => (
|
||||
<Tab
|
||||
value={item}
|
||||
label={item.label}
|
||||
data-testid={`tab-link-for-${item.id}`}
|
||||
active={item.isActive.get()}
|
||||
/>
|
||||
));
|
||||
|
||||
export const PreferencesNavigation = withInjectables<Dependencies>(
|
||||
NonInjectedPreferencesNavigation,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
navigationItems: di.inject(preferenceNavigationItemsInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const PreferencesNavigation = () => {
|
||||
return (
|
||||
<Tabs
|
||||
className="flex column"
|
||||
scrollable={false}
|
||||
onChange={(item: PreferenceNavigationItem) => item.navigate()}
|
||||
>
|
||||
<GeneralNavGroup/>
|
||||
<ExtensionsNavGroup/>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
@ -24,6 +24,7 @@ const proxyPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "proxy",
|
||||
label: "Proxy",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
isVisible: computed(() => true),
|
||||
|
||||
@ -32,6 +32,7 @@ const terminalPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "telemetry",
|
||||
label: "Telemetry",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ const terminalPreferencesNavigationItemInjectable = getInjectable({
|
||||
return {
|
||||
id: "terminal",
|
||||
label: "Terminal",
|
||||
parent: "general",
|
||||
navigate: navigateToPreferenceTab(route),
|
||||
isActive: routeIsActive,
|
||||
isVisible: computed(() => true),
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
.sidebar {
|
||||
width: 218px;
|
||||
padding: 60px 0 60px 20px;
|
||||
padding: 60px 10px 60px 20px;
|
||||
|
||||
h2 {
|
||||
font-size: 15px;
|
||||
@ -52,10 +52,6 @@
|
||||
margin-right: 20px;
|
||||
height: 1px;
|
||||
border-top: thin solid var(--hrColor);
|
||||
|
||||
&:first-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.Tabs {
|
||||
@ -63,7 +59,6 @@
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
line-height: 16px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textColorPrimary);
|
||||
|
||||
@ -76,14 +71,10 @@
|
||||
padding: 6px 10px;
|
||||
margin-bottom: 2px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
white-space: normal;
|
||||
|
||||
&::after {
|
||||
content: none;
|
||||
|
||||
@ -55,6 +55,9 @@ import { openMenu } from "react-select-event";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { StatusBar } from "../status-bar/status-bar";
|
||||
import lensProxyPortInjectable from "../../../main/lens-proxy/lens-proxy-port.injectable";
|
||||
import type { Route } from "../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { NavigateToRouteOptions } from "../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { navigateToRouteInjectionToken } from "../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import type { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||
import trayMenuItemsInjectable from "../../../main/tray/tray-menu-item/tray-menu-items.injectable";
|
||||
import type { LensExtension } from "../../../extensions/lens-extension";
|
||||
@ -100,6 +103,7 @@ export interface ApplicationBuilder {
|
||||
preferences: {
|
||||
close: () => void;
|
||||
navigate: () => void;
|
||||
navigateTo: (route: Route<any>, params: Partial<NavigateToRouteOptions<any>>) => void;
|
||||
navigation: {
|
||||
click: (id: string) => void;
|
||||
};
|
||||
@ -332,6 +336,12 @@ export const getApplicationBuilder = () => {
|
||||
navigateToPreferences();
|
||||
},
|
||||
|
||||
navigateTo: (route: Route<any>, params: Partial<NavigateToRouteOptions<any>>) => {
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
|
||||
navigateToRoute(route, params);
|
||||
},
|
||||
|
||||
navigation: {
|
||||
click: (id: string) => {
|
||||
const link = rendered.queryByTestId(`tab-link-for-${id}`);
|
||||
@ -546,7 +556,7 @@ const disableExtensionsFor = <T extends ObservableSet>(
|
||||
runInAction(() => {
|
||||
extension.deregister();
|
||||
|
||||
extensionState.delete(extension);
|
||||
extensionState.delete(instance);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -9,7 +9,7 @@ import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
|
||||
export const getDi = () => {
|
||||
const di = createContainer();
|
||||
const di = createContainer("renderer");
|
||||
|
||||
registerMobX(di);
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
|
||||
doGeneralOverrides = false,
|
||||
} = opts;
|
||||
|
||||
const di = createContainer();
|
||||
const di = createContainer("renderer");
|
||||
|
||||
registerMobX(di);
|
||||
|
||||
|
||||
54
yarn.lock
54
yarn.lock
@ -1189,46 +1189,46 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@ogre-tools/fp@8.0.0", "@ogre-tools/fp@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/fp/-/fp-8.0.0.tgz#dd2319a96ce3d2edd3ee2bc2acca07a94a77bf3b"
|
||||
integrity sha512-8OpGUbG3avGtx6ASz3XNnK/KCyPW25RPp8oYzzU0zihKU5D4QKHy9qNkQ3npurzeg4d1k4BsgkeX+805nqtZOA==
|
||||
"@ogre-tools/fp@9.0.0", "@ogre-tools/fp@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/fp/-/fp-9.0.0.tgz#926cd4f13b52961156161feeeafddf22a0ad39c0"
|
||||
integrity sha512-kMUgzhdjHuph0UWteOfyXNGBavZJX23NOA5su6fx9NdTzWhl9yB5Uf6Q//nOvL9COftjZDwnAgIaDU4MPdjyqA==
|
||||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@ogre-tools/injectable-extension-for-auto-registration@8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-auto-registration/-/injectable-extension-for-auto-registration-8.0.0.tgz#3a443f1f1c9b564baa78cca6a3c81ac4102660b0"
|
||||
integrity sha512-DX1bxn8mDwek+W/SaI5WmDHmkY3B3njs3X4pOvqRtiMis3GaWHzeCZeK3q3Iv5cd14FTW8AsfKtujPmLklNf/A==
|
||||
"@ogre-tools/injectable-extension-for-auto-registration@9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-auto-registration/-/injectable-extension-for-auto-registration-9.0.0.tgz#69463737ef4f7777db4703964b8a72a5fb82d6b3"
|
||||
integrity sha512-+3I9Z0GfA04zZoj7Nw5WhJLDFLJgr5xv8Kp1zPDuT9/OvE9EA6hzAqakMDLbvn1zZOJjkJCGk44x6UjSQJp/9w==
|
||||
dependencies:
|
||||
"@ogre-tools/fp" "^8.0.0"
|
||||
"@ogre-tools/injectable" "^8.0.0"
|
||||
"@ogre-tools/fp" "^9.0.0"
|
||||
"@ogre-tools/injectable" "^9.0.0"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@ogre-tools/injectable-extension-for-mobx@8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-mobx/-/injectable-extension-for-mobx-8.0.0.tgz#80ff506011e078050dd8dcb72660d17181db6d34"
|
||||
integrity sha512-m8gU3cEFHl9IMZLcvvoS7hVxS6p6nG3jdf6fY6MUZE0u9hx4bZuUdWYoylGQizy0FyRFQ2/m5xhTH2VdtXqx8w==
|
||||
"@ogre-tools/injectable-extension-for-mobx@9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-mobx/-/injectable-extension-for-mobx-9.0.0.tgz#ed14df39b266e521272977821d3e05bcbd647577"
|
||||
integrity sha512-9Hrtr7AdibcD+Fqn2qNsjiOUakAACO55TB1IqNsOJMMuqQHVB5SFZTHBzdVRqqqY2MwQvWYvd4xfy+beItD/xw==
|
||||
dependencies:
|
||||
"@ogre-tools/fp" "^8.0.0"
|
||||
"@ogre-tools/injectable" "^8.0.0"
|
||||
"@ogre-tools/fp" "^9.0.0"
|
||||
"@ogre-tools/injectable" "^9.0.0"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@ogre-tools/injectable-react@8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-react/-/injectable-react-8.0.0.tgz#b2d8db4bb697ba2822d71ec73e6cabee30f70f34"
|
||||
integrity sha512-rZa38fm3UzGa/09qC765Za8xJiSPOYHJGsob8UOt2JQIt/BecTNXPMHexfxy9W+DIdAer+YruUgedChdk9nvdQ==
|
||||
"@ogre-tools/injectable-react@9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-react/-/injectable-react-9.0.0.tgz#c5c510e893a5c1d7994d8709f70606967cabdec2"
|
||||
integrity sha512-vGQrwkcWibRUWFPbu392riBYY4dXK051FxwyMsDYNRqmvaLo8HuumwjzS1DWS7db/P9Li+Kc+Ms670xIZepcpA==
|
||||
dependencies:
|
||||
"@ogre-tools/fp" "^8.0.0"
|
||||
"@ogre-tools/injectable" "^8.0.0"
|
||||
"@ogre-tools/fp" "^9.0.0"
|
||||
"@ogre-tools/injectable" "^9.0.0"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@ogre-tools/injectable@8.0.0", "@ogre-tools/injectable@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable/-/injectable-8.0.0.tgz#ea4f98bd2466149add94d4f6a9beb7be03729da7"
|
||||
integrity sha512-59p+8uGqwVQ5IpGpgfn3RA+wXzn1tjnPdFWO3GLEgjyp5dWBaMKufCpCFRvvb9sP6B68qo19aLfy/uSm4AXduw==
|
||||
"@ogre-tools/injectable@9.0.0", "@ogre-tools/injectable@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable/-/injectable-9.0.0.tgz#0819bc7b5fbae0a467f3250b10b4adb003268067"
|
||||
integrity sha512-z9X86Q9AEkkilLu9V33j/aXv/IUoG944AdfN6WX2zZgJqRNjESN9spoOMqdKqib6JmEjCRxpMvaMwHLQSh14fg==
|
||||
dependencies:
|
||||
"@ogre-tools/fp" "^8.0.0"
|
||||
"@ogre-tools/fp" "^9.0.0"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@panva/asn1.js@^1.0.0":
|
||||
|
||||
Loading…
Reference in New Issue
Block a user