mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Restructure to monorepo (#6907)
* wip: restructure to monorepo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor create-release-pr to a package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * github workflow fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix typo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * add webpack-env types to core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix github workflows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor/fix integration tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * lint fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * yarn run dev Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * eslint settings for vscode Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * move templates to right package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * open-lens build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * integration test fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix nx task dependencies Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * use bash shell for unit tests in test workflow Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix test:unit for windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix build:app on windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove ELECTRON_BUILDER_EXTRA_ARGS Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * sync src/ from master Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove Makefile from core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
0066ca4ea2
commit
2657df2293
3321 files changed
+28699
-11447
No files matched your search
+132
@@ -0,0 +1,132 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`application-menu, given platform is 'darwin' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> mac",
|
||||
"root -> mac -> about",
|
||||
"root -> mac -> separator-1",
|
||||
"root -> mac -> navigate-to-preferences",
|
||||
"root -> mac -> navigate-to-extensions",
|
||||
"root -> mac -> separator-2",
|
||||
"root -> mac -> services",
|
||||
"root -> mac -> separator-3",
|
||||
"root -> mac -> hide",
|
||||
"root -> mac -> hide-others",
|
||||
"root -> mac -> unhide",
|
||||
"root -> mac -> separator-4",
|
||||
"root -> mac -> quit",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> separator-1-for-file",
|
||||
"root -> file -> close-window",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`application-menu, given platform is 'linux' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> navigate-to-preferences",
|
||||
"root -> file -> navigate-to-extensions",
|
||||
"root -> file -> quit",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
"root -> help -> about",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`application-menu, given platform is 'win32' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> navigate-to-preferences",
|
||||
"root -> file -> navigate-to-extensions",
|
||||
"root -> file -> quit",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
"root -> help -> about",
|
||||
]
|
||||
`;
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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 { noop } from "lodash/fp";
|
||||
import { runInAction } from "mobx";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
|
||||
import applicationMenuItemInjectionToken from "./main/menu-items/application-menu-item-injection-token";
|
||||
import logErrorInjectable from "../../common/log-error.injectable";
|
||||
|
||||
describe("application-menu-in-legacy-extension-api", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let logErrorMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(
|
||||
(mainDi) => {
|
||||
runInAction(() => {
|
||||
mainDi.register(
|
||||
someTopMenuItemInjectable,
|
||||
someNonExtensionBasedMenuItemInjectable,
|
||||
);
|
||||
});
|
||||
|
||||
logErrorMock = jest.fn();
|
||||
|
||||
mainDi.override(logErrorInjectable, () => logErrorMock);
|
||||
},
|
||||
);
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
describe("when extension with application menu items is enabled", () => {
|
||||
let onClickMock: jest.Mock;
|
||||
let testExtensionOptions: FakeExtensionOptions;
|
||||
|
||||
beforeEach(() => {
|
||||
onClickMock = jest.fn();
|
||||
|
||||
testExtensionOptions = {
|
||||
id: "some-test-extension",
|
||||
name: "some-extension-name",
|
||||
|
||||
mainOptions: {
|
||||
appMenus: [
|
||||
{
|
||||
id: "some-non-shown-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: noop,
|
||||
label: "Irrelevant",
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-clickable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: onClickMock,
|
||||
},
|
||||
|
||||
{
|
||||
parentId: "some-top-menu-item",
|
||||
type: "separator",
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-os-action-menu-item-id",
|
||||
parentId: "some-top-menu-item",
|
||||
role: "help",
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-submenu-with-explicit-children",
|
||||
parentId: "some-top-menu-item",
|
||||
|
||||
submenu: [
|
||||
{ id: "some-explicit-child", label: "Some explicit child", click: noop },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("related menu items exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-clickable-item"],
|
||||
// Note: anonymous index "1" is used by the non-visible menu item.
|
||||
["root", "some-top-menu-item", "some-extension-name/2-separator"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-os-action-menu-item-id"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children", "some-extension-name/some-submenu-with-explicit-children/some-explicit-child"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("when the extension-based clickable menu item is clicked, does so", () => {
|
||||
builder.applicationMenu.click(
|
||||
"root", "some-top-menu-item", "some-extension-name/some-clickable-item",
|
||||
);
|
||||
|
||||
expect(onClickMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when the extension is disabled", () => {
|
||||
beforeEach(() => {
|
||||
builder.extensions.disable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("when related menu items no longer exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([]);
|
||||
});
|
||||
|
||||
it("when the extension is enabled again, also related menu items exist again", () => {
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-clickable-item"],
|
||||
["root", "some-top-menu-item", "some-extension-name/2-separator"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-os-action-menu-item-id"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children", "some-extension-name/some-submenu-with-explicit-children/some-explicit-child"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when extension with unrecognizable application menu items is enabled", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const testExtensionOptions: FakeExtensionOptions = {
|
||||
id: "some-test-extension",
|
||||
name: "some-extension-name",
|
||||
|
||||
mainOptions: {
|
||||
appMenus: [
|
||||
{
|
||||
id: "some-recognizable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: noop,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-unrecognizable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
// Note: there is no way to recognize this
|
||||
// click: noop,
|
||||
// role: "help"
|
||||
// submenu: []
|
||||
// type: "separator"
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("only recognizable menu items from extension exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-recognizable-item"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("logs about the unrecognizable item", () => {
|
||||
expect(logErrorMock).toHaveBeenCalledWith(
|
||||
'[MENU]: Tried to register menu item "some-extension-name/some-unrecognizable-item" but it is not recognizable as any of ApplicationMenuItemTypes',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const someTopMenuItemInjectable = getInjectable({
|
||||
id: "some-top-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-top-menu-item",
|
||||
parentId: "root" as const,
|
||||
kind: "top-level-menu" as const,
|
||||
label: "Some existing root menu item",
|
||||
orderNumber: 42,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
const someNonExtensionBasedMenuItemInjectable = getInjectable({
|
||||
id: "some-non-extension-based-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-non-extension-based-menu-item",
|
||||
parentId: "some-top-menu-item",
|
||||
kind: "clickable-menu-item" as const,
|
||||
label: "Some menu item",
|
||||
onClick: () => {},
|
||||
orderNumber: 42,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import populateApplicationMenuInjectable from "./main/populate-application-menu.injectable";
|
||||
import { advanceFakeTime, testUsingFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import { getCompositePaths } from "../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import platformInjectable, { allPlatforms } from "../../common/vars/platform.injectable";
|
||||
|
||||
describe.each(allPlatforms)("application-menu, given platform is '%s'", (platform) => {
|
||||
let builder: ApplicationBuilder;
|
||||
let populateApplicationMenuMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
testUsingFakeTime();
|
||||
|
||||
populateApplicationMenuMock = jest.fn();
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(platformInjectable, () => platform);
|
||||
|
||||
mainDi.override(
|
||||
populateApplicationMenuInjectable,
|
||||
() => populateApplicationMenuMock,
|
||||
);
|
||||
});
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
it("when insufficient time passes, does not populate menu items yet", () => {
|
||||
advanceFakeTime(99);
|
||||
|
||||
expect(populateApplicationMenuMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("given enough time passes", () => {
|
||||
let applicationMenuPaths: string[][];
|
||||
|
||||
beforeEach(() => {
|
||||
advanceFakeTime(100);
|
||||
applicationMenuPaths = getCompositePaths(
|
||||
populateApplicationMenuMock.mock.calls[0][0],
|
||||
);
|
||||
});
|
||||
|
||||
it("populates application menu with at least something", () => {
|
||||
expect(applicationMenuPaths.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("populates application menu", () => {
|
||||
expect(applicationMenuPaths.map(x => x.join(" -> "))).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import populateApplicationMenuInjectable from "./main/populate-application-menu.injectable";
|
||||
import { advanceFakeTime, testUsingFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import { getCompositePaths } from "../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import applicationMenuItemInjectionToken from "./main/menu-items/application-menu-item-injection-token";
|
||||
import { runInAction } from "mobx";
|
||||
import logErrorInjectable from "../../common/log-error.injectable";
|
||||
|
||||
describe("handling-of-orphan-application-menu-items, given orphan menu item", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let populateApplicationMenuMock: jest.Mock;
|
||||
let logErrorMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
testUsingFakeTime();
|
||||
|
||||
populateApplicationMenuMock = jest.fn();
|
||||
logErrorMock = jest.fn();
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
const someOrphanMenuItemInjectable = getInjectable({
|
||||
id: "some-orphan-menu-item",
|
||||
instantiate: () => ({
|
||||
kind: "sub-menu" as const,
|
||||
id: "some-item-id",
|
||||
// Note: unknown id makes this item an orphan.
|
||||
parentId: "some-unknown-parent-id",
|
||||
orderNumber: 0,
|
||||
label: "irrelevant",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
runInAction(() => {
|
||||
mainDi.register(someOrphanMenuItemInjectable);
|
||||
});
|
||||
|
||||
mainDi.override(logErrorInjectable, () => logErrorMock);
|
||||
|
||||
mainDi.override(
|
||||
populateApplicationMenuInjectable,
|
||||
() => populateApplicationMenuMock,
|
||||
);
|
||||
});
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
describe("given some time passes", () => {
|
||||
let applicationMenuPaths: string[][];
|
||||
|
||||
beforeEach(() => {
|
||||
advanceFakeTime(100);
|
||||
|
||||
applicationMenuPaths = getCompositePaths(
|
||||
populateApplicationMenuMock.mock.calls[0][0],
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps showing the other application menu items without throwing", () => {
|
||||
expect(applicationMenuPaths.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("does not show orphan application menu item", () => {
|
||||
expect(applicationMenuPaths.find(x => x.join(".").endsWith("some-item-id")));
|
||||
});
|
||||
|
||||
it("logs about bad menu item", () => {
|
||||
expect(logErrorMock).toHaveBeenCalledWith('[MENU]: cannot render menu item for missing parentIds: "some-unknown-parent-id"');
|
||||
});
|
||||
});
|
||||
});
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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 applicationMenuItemsInjectable from "./application-menu-items.injectable";
|
||||
import type { Composite } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import { getCompositeFor } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import { computed } from "mobx";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import type { ApplicationMenuItemTypes } from "./menu-items/application-menu-item-injection-token";
|
||||
import type { RootComposite } from "../../../common/utils/composite/interfaces";
|
||||
import type { Discriminable } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
import { orderByOrderNumber } from "../../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
import logErrorInjectable from "../../../common/log-error.injectable";
|
||||
import { isShown } from "../../../common/utils/composable-responsibilities/showable/showable";
|
||||
|
||||
export type MenuItemRoot = Discriminable<"root"> & RootComposite<"root">;
|
||||
|
||||
const applicationMenuItemCompositeInjectable = getInjectable({
|
||||
id: "application-menu-item-composite",
|
||||
|
||||
instantiate: (di) => {
|
||||
const menuItems = di.inject(applicationMenuItemsInjectable);
|
||||
const logError = di.inject(logErrorInjectable);
|
||||
|
||||
return computed((): Composite<ApplicationMenuItemTypes | MenuItemRoot> => {
|
||||
const items = menuItems.get();
|
||||
|
||||
return pipeline(
|
||||
[
|
||||
{
|
||||
parentId: undefined,
|
||||
id: "root",
|
||||
kind: "root",
|
||||
} as const,
|
||||
|
||||
...items,
|
||||
],
|
||||
|
||||
getCompositeFor({
|
||||
getId: (x) => x.id,
|
||||
getParentId: (x) => x.parentId,
|
||||
transformChildren: (children) =>
|
||||
pipeline(
|
||||
children,
|
||||
orderByOrderNumber,
|
||||
(children) => children.filter(isShown),
|
||||
),
|
||||
|
||||
handleMissingParentIds: ({ missingParentIds }) => {
|
||||
logError(
|
||||
`[MENU]: cannot render menu item for missing parentIds: "${missingParentIds.join(
|
||||
'", "',
|
||||
)}"`,
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default applicationMenuItemCompositeInjectable;
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { computed } from "mobx";
|
||||
import type { Injectable } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { LensExtension } from "../../../extensions/lens-extension";
|
||||
import type { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||
import type {
|
||||
ApplicationMenuItemTypes,
|
||||
ClickableMenuItem,
|
||||
OsActionMenuItem,
|
||||
Separator,
|
||||
} from "./menu-items/application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./menu-items/application-menu-item-injection-token";
|
||||
import type { MenuRegistration } from "./menu-registration";
|
||||
import logErrorInjectable from "../../../common/log-error.injectable";
|
||||
|
||||
const applicationMenuItemRegistratorInjectable = getInjectable({
|
||||
id: "application-menu-item-registrator",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logError = di.inject(logErrorInjectable);
|
||||
const toRecursedInjectables = toRecursedInjectablesFor(logError);
|
||||
|
||||
return (ext: LensExtension) => {
|
||||
const mainExtension = ext as LensMainExtension;
|
||||
|
||||
return computed(() => {
|
||||
const appMenus = Array.isArray(mainExtension.appMenus) ? mainExtension.appMenus : mainExtension.appMenus.get();
|
||||
|
||||
return appMenus.flatMap(
|
||||
toRecursedInjectables([mainExtension.sanitizedExtensionId]),
|
||||
);
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: extensionRegistratorInjectionToken,
|
||||
});
|
||||
|
||||
export default applicationMenuItemRegistratorInjectable;
|
||||
|
||||
const toRecursedInjectablesFor = (logError: (errorMessage: string) => void) => {
|
||||
const toRecursedInjectables = (previousIdPath: string[]) =>
|
||||
(
|
||||
registration: MenuRegistration,
|
||||
index: number,
|
||||
// Todo: new version of injectable would require less type parameters with defaults.
|
||||
): Injectable<
|
||||
ApplicationMenuItemTypes,
|
||||
ApplicationMenuItemTypes,
|
||||
void
|
||||
>[] => {
|
||||
const previousIdPathString = previousIdPath.join("/");
|
||||
const registrationId = registration.id || index.toString();
|
||||
const currentIdPath = [...previousIdPath, registrationId];
|
||||
const currentIdPathString = currentIdPath.join("/");
|
||||
const parentId = registration.parentId || previousIdPathString;
|
||||
|
||||
const menuItem = getApplicationMenuItem({
|
||||
registration,
|
||||
parentId,
|
||||
currentIdPathString,
|
||||
index,
|
||||
});
|
||||
|
||||
if (!menuItem) {
|
||||
logError(`[MENU]: Tried to register menu item "${currentIdPathString}" but it is not recognizable as any of ApplicationMenuItemTypes`);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
getInjectable({
|
||||
id: `${currentIdPathString}/application-menu-item`,
|
||||
|
||||
instantiate: () => menuItem,
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
}),
|
||||
|
||||
...((registration.submenu as MenuRegistration[])
|
||||
? (registration.submenu as MenuRegistration[]).flatMap(
|
||||
toRecursedInjectables(currentIdPath),
|
||||
)
|
||||
: []),
|
||||
];
|
||||
};
|
||||
|
||||
return toRecursedInjectables;
|
||||
};
|
||||
|
||||
const getApplicationMenuItem = ({
|
||||
registration,
|
||||
index,
|
||||
currentIdPathString,
|
||||
parentId,
|
||||
}: {
|
||||
registration: MenuRegistration;
|
||||
index: number;
|
||||
currentIdPathString: string;
|
||||
parentId: string;
|
||||
}): ApplicationMenuItemTypes | undefined => {
|
||||
const orderNumber = 1000 + index * 10;
|
||||
|
||||
if (registration.type === "separator") {
|
||||
return {
|
||||
kind: "separator" as const,
|
||||
id: `${currentIdPathString}-separator`,
|
||||
parentId,
|
||||
orderNumber,
|
||||
} as Separator;
|
||||
}
|
||||
|
||||
if (registration.submenu) {
|
||||
return {
|
||||
kind: "sub-menu" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
label: registration.label || "",
|
||||
};
|
||||
}
|
||||
|
||||
if (registration.click) {
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
// Todo: hide electron events from this abstraction.
|
||||
onClick: registration.click,
|
||||
label: registration.label,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
|
||||
...(registration.accelerator
|
||||
? { keyboardShortcut: registration.accelerator as string }
|
||||
: {}),
|
||||
} as ClickableMenuItem;
|
||||
}
|
||||
|
||||
if (registration.role) {
|
||||
return {
|
||||
kind: "os-action-menu-item" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
label: registration.label,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
actionName: registration.role,
|
||||
|
||||
...(registration.accelerator
|
||||
? { keyboardShortcut: registration.accelerator as string }
|
||||
: {}),
|
||||
} as OsActionMenuItem;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 type { MenuItemConstructorOptions } from "electron";
|
||||
import { computed } from "mobx";
|
||||
import applicationMenuItemInjectionToken from "./menu-items/application-menu-item-injection-token";
|
||||
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
|
||||
export interface MenuItemOpts extends MenuItemConstructorOptions {
|
||||
submenu?: MenuItemConstructorOptions[];
|
||||
}
|
||||
|
||||
const applicationMenuItemsInjectable = getInjectable({
|
||||
id: "application-menu-items",
|
||||
|
||||
instantiate: (di) => {
|
||||
const computedInjectMany = di.inject(computedInjectManyInjectable);
|
||||
|
||||
return computed(() =>
|
||||
computedInjectMany(applicationMenuItemInjectionToken).get(),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export default applicationMenuItemsInjectable;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 { autorun } from "mobx";
|
||||
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
|
||||
import populateApplicationMenuInjectable from "./populate-application-menu.injectable";
|
||||
import applicationMenuItemCompositeInjectable from "./application-menu-item-composite.injectable";
|
||||
|
||||
const applicationMenuReactivityInjectable = getInjectable({
|
||||
id: "application-menu-reactivity",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
|
||||
const populateApplicationMenu = di.inject(populateApplicationMenuInjectable);
|
||||
|
||||
return getStartableStoppable(
|
||||
"application-menu-reactivity",
|
||||
() => autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), {
|
||||
delay: 100,
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default applicationMenuReactivityInjectable;
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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 { BrowserWindow, KeyboardEvent, MenuItemConstructorOptions, MenuItem as ElectronMenuItem } from "electron";
|
||||
import type { SetOptional } from "type-fest";
|
||||
import type { ChildOfParentComposite, ParentOfChildComposite } from "../../../../common/utils/composite/interfaces";
|
||||
import type { MaybeShowable } from "../../../../common/utils/composable-responsibilities/showable/showable";
|
||||
import type { Discriminable } from "../../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
import type { Orderable } from "../../../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
|
||||
export interface MayHaveKeyboardShortcut {
|
||||
keyboardShortcut?: string;
|
||||
}
|
||||
|
||||
export interface ElectronClickable {
|
||||
// TODO: This leaky abstraction is exposed in Extension API, therefore cannot be updated
|
||||
onClick: (menuItem: ElectronMenuItem, browserWindow: (BrowserWindow) | (undefined), event: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
export interface Labeled {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface MaybeLabeled extends SetOptional<Labeled, "label"> {}
|
||||
|
||||
type ApplicationMenuItemType<T extends string> =
|
||||
// Note: "kind" is being used for Discriminated unions of TypeScript to achieve type narrowing.
|
||||
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions
|
||||
& Discriminable<T>
|
||||
& ParentOfChildComposite
|
||||
& ChildOfParentComposite
|
||||
& MaybeShowable
|
||||
& Orderable;
|
||||
|
||||
export type TopLevelMenu =
|
||||
& ApplicationMenuItemType<"top-level-menu">
|
||||
& { parentId: "root" }
|
||||
& Labeled
|
||||
& MayHaveElectronRole;
|
||||
|
||||
interface MayHaveElectronRole {
|
||||
role?: ElectronRoles;
|
||||
}
|
||||
|
||||
type ElectronRoles = Exclude<MenuItemConstructorOptions["role"], undefined>;
|
||||
|
||||
export type SubMenu =
|
||||
& ApplicationMenuItemType<"sub-menu">
|
||||
& Labeled
|
||||
& ChildOfParentComposite;
|
||||
|
||||
export type ClickableMenuItem =
|
||||
& ApplicationMenuItemType<"clickable-menu-item">
|
||||
& MenuItem
|
||||
& Labeled
|
||||
& ElectronClickable;
|
||||
|
||||
export type OsActionMenuItem =
|
||||
& ApplicationMenuItemType<"os-action-menu-item">
|
||||
& MenuItem
|
||||
& MaybeLabeled
|
||||
& TriggersElectronAction;
|
||||
|
||||
type MenuItem =
|
||||
& ChildOfParentComposite
|
||||
& MayHaveKeyboardShortcut;
|
||||
|
||||
interface TriggersElectronAction {
|
||||
actionName: ElectronRoles;
|
||||
}
|
||||
|
||||
// Todo: SeparatorMenuItem
|
||||
export type Separator =
|
||||
& ApplicationMenuItemType<"separator">
|
||||
& ChildOfParentComposite;
|
||||
|
||||
export type ApplicationMenuItemTypes =
|
||||
| TopLevelMenu
|
||||
| SubMenu
|
||||
| OsActionMenuItem
|
||||
| ClickableMenuItem
|
||||
| Separator
|
||||
;
|
||||
|
||||
const applicationMenuItemInjectionToken = getInjectionToken<ApplicationMenuItemTypes>({
|
||||
id: "application-menu-item-injection-token",
|
||||
});
|
||||
|
||||
export default applicationMenuItemInjectionToken;
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const editMenuItemInjectable = getInjectable({
|
||||
id: "edit-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "edit",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 30,
|
||||
label: "Edit",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default editMenuItemInjectable;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getApplicationMenuOperationSystemActionInjectable } from "../../get-application-menu-operation-system-action-injectable";
|
||||
import { getApplicationMenuSeparatorInjectable } from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const actionForUndo = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "undo",
|
||||
parentId: "edit",
|
||||
orderNumber: 10,
|
||||
actionName: "undo",
|
||||
});
|
||||
|
||||
export const actionForRedo = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "redo",
|
||||
parentId: "edit",
|
||||
orderNumber: 20,
|
||||
actionName: "redo",
|
||||
});
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-in-edit",
|
||||
parentId: "edit",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const actionForCut = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "cut",
|
||||
parentId: "edit",
|
||||
orderNumber: 40,
|
||||
actionName: "cut",
|
||||
});
|
||||
|
||||
export const actionForCopy = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "copy",
|
||||
parentId: "edit",
|
||||
orderNumber: 50,
|
||||
actionName: "copy",
|
||||
});
|
||||
|
||||
export const actionForPaste = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "paste",
|
||||
parentId: "edit",
|
||||
orderNumber: 60,
|
||||
actionName: "paste",
|
||||
});
|
||||
|
||||
export const actionForDelete = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "delete",
|
||||
parentId: "edit",
|
||||
orderNumber: 70,
|
||||
actionName: "delete",
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2-in-edit",
|
||||
parentId: "edit",
|
||||
orderNumber: 80,
|
||||
});
|
||||
|
||||
export const actionForSelectAll = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "selectAll",
|
||||
parentId: "edit",
|
||||
orderNumber: 90,
|
||||
actionName: "selectAll",
|
||||
});
|
||||
|
||||
+32
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToAddClusterInjectable from "../../../../../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
|
||||
|
||||
const addClusterMenuItemInjectable = getInjectable({
|
||||
id: "add-cluster-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "file",
|
||||
id: "add-cluster",
|
||||
orderNumber: 10,
|
||||
label: "Add Cluster",
|
||||
keyboardShortcut: "CmdOrCtrl+Shift+A",
|
||||
|
||||
onClick: () => {
|
||||
navigateToAddCluster();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default addClusterMenuItemInjectable;
|
||||
+30
@@ -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 } from "@ogre-tools/injectable";
|
||||
import applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const closeWindowMenuItemInjectable = getInjectable({
|
||||
id: "close-window-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
id: "close-window",
|
||||
kind: "os-action-menu-item" as const,
|
||||
parentId: "file",
|
||||
orderNumber: 60,
|
||||
actionName: "close" as const,
|
||||
label: "Close Window",
|
||||
keyboardShortcut: "Shift+Cmd+W",
|
||||
isShown: isMac,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default closeWindowMenuItemInjectable;
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const fileMenuItemInjectable = getInjectable({
|
||||
id: "file-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "file",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 20,
|
||||
label: "File",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default fileMenuItemInjectable;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-for-file",
|
||||
parentId: "file",
|
||||
orderNumber: 20,
|
||||
isShownOnlyOnMac: true,
|
||||
});
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 type { OsActionMenuItem } from "./application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./application-menu-item-injection-token";
|
||||
|
||||
const getApplicationMenuOperationSystemActionInjectable = ({
|
||||
id,
|
||||
...rest
|
||||
}: Omit<OsActionMenuItem, "kind" >) =>
|
||||
getInjectable({
|
||||
id: `application-menu-operation-system-action/${id}`,
|
||||
|
||||
instantiate: () => ({
|
||||
...rest,
|
||||
id,
|
||||
kind: "os-action-menu-item" as const,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export { getApplicationMenuOperationSystemActionInjectable };
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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 type { Separator } from "./application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const getApplicationMenuSeparatorInjectable = ({
|
||||
id,
|
||||
isShownOnlyOnMac = false,
|
||||
...rest
|
||||
}: { isShownOnlyOnMac?: boolean } & Omit<
|
||||
Separator,
|
||||
"kind" | "isShown"
|
||||
>) =>
|
||||
getInjectable({
|
||||
id: `application-menu-separator/${id}`,
|
||||
|
||||
instantiate: (di) => {
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const isShown = isShownOnlyOnMac ? isMac : true;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
id,
|
||||
kind: "separator" as const,
|
||||
isShown,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export { getApplicationMenuSeparatorInjectable };
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const helpMenuItemInjectable = getInjectable({
|
||||
id: "help-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "help",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 50,
|
||||
label: "Help",
|
||||
role: "help" as const,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default helpMenuItemInjectable;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToWelcomeInjectable from "../../../../../../common/front-end-routing/routes/welcome/navigate-to-welcome.injectable";
|
||||
|
||||
const navigateToWelcomeMenuItem = getInjectable({
|
||||
id: "navigate-to-welcome-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToWelcome = di.inject(navigateToWelcomeInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "navigate-to-welcome",
|
||||
orderNumber: 10,
|
||||
label: "Welcome",
|
||||
|
||||
onClick: () => {
|
||||
navigateToWelcome();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToWelcomeMenuItem;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { docsUrl } from "../../../../../../common/vars";
|
||||
import openLinkInBrowserInjectable from "../../../../../../common/utils/open-link-in-browser.injectable";
|
||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
|
||||
const openDocumentationMenuItemInjectable = getInjectable({
|
||||
id: "open-documentation-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "open-documentation",
|
||||
orderNumber: 20,
|
||||
label: "Documentation",
|
||||
|
||||
// TODO: Convert to async/await
|
||||
onClick: () => {
|
||||
openLinkInBrowser(docsUrl).catch((error) => {
|
||||
logger.error("[MENU]: failed to open browser", { error });
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openDocumentationMenuItemInjectable;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { supportUrl } from "../../../../../../common/vars";
|
||||
import openLinkInBrowserInjectable from "../../../../../../common/utils/open-link-in-browser.injectable";
|
||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
|
||||
const openSupportItemInjectable = getInjectable({
|
||||
id: "open-support-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "open-support",
|
||||
orderNumber: 30,
|
||||
label: "Support",
|
||||
|
||||
// TODO: Convert to async/await
|
||||
onClick: () => {
|
||||
openLinkInBrowser(supportUrl).catch((error) => {
|
||||
logger.error("[MENU]: failed to open browser", { error });
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openSupportItemInjectable;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToExtensionsInjectable from "../../../../../../common/front-end-routing/routes/extensions/navigate-to-extensions.injectable";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const navigateToExtensionsMenuItem = getInjectable({
|
||||
id: "navigate-to-extensions-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToExtensions = di.inject(navigateToExtensionsInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: isMac ? "mac" : "file",
|
||||
id: "navigate-to-extensions",
|
||||
orderNumber: isMac ? 50 : 40,
|
||||
label: "Extensions",
|
||||
keyboardShortcut: isMac ? "CmdOrCtrl+Shift+E" : "Ctrl+Shift+E",
|
||||
|
||||
onClick: () => {
|
||||
navigateToExtensions();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToExtensionsMenuItem;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuOperationSystemActionInjectable,
|
||||
} from "../../get-application-menu-operation-system-action-injectable";
|
||||
|
||||
export const actionForServices = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "services",
|
||||
parentId: "mac",
|
||||
orderNumber: 80,
|
||||
actionName: "services",
|
||||
});
|
||||
|
||||
export const actionForHide = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "hide",
|
||||
parentId: "mac",
|
||||
orderNumber: 100,
|
||||
actionName: "hide",
|
||||
});
|
||||
|
||||
export const actionForHideOthers = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "hide-others",
|
||||
parentId: "mac",
|
||||
orderNumber: 110,
|
||||
actionName: "hideOthers",
|
||||
});
|
||||
|
||||
export const actionForUnhide = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "unhide",
|
||||
parentId: "mac",
|
||||
orderNumber: 120,
|
||||
actionName: "unhide",
|
||||
});
|
||||
+30
@@ -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 } from "@ogre-tools/injectable";
|
||||
import applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
import appNameInjectable from "../../../../../common/vars/app-name.injectable";
|
||||
import isMacInjectable from "../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const primaryMenuItemInjectable = getInjectable({
|
||||
id: "primary-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const appName = di.inject(appNameInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "top-level-menu" as const,
|
||||
parentId: "root" as const,
|
||||
id: "mac",
|
||||
orderNumber: 10,
|
||||
label: appName,
|
||||
isShown: isMac,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default primaryMenuItemInjectable;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import stopServicesAndExitAppInjectable from "../../../../../../main/stop-services-and-exit-app.injectable";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const quitApplicationMenuItemInjectable = getInjectable({
|
||||
id: "quit-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: "quit",
|
||||
label: "Quit",
|
||||
|
||||
parentId: isMac ? "mac" : "file",
|
||||
orderNumber: isMac ? 140 : 70,
|
||||
keyboardShortcut: isMac ? "Cmd+Q" : "Alt+F4",
|
||||
|
||||
onClick: () => {
|
||||
stopServicesAndExitApp();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default quitApplicationMenuItemInjectable;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1",
|
||||
parentId: "mac",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2",
|
||||
parentId: "mac",
|
||||
orderNumber: 70,
|
||||
});
|
||||
|
||||
export const separator3 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-3",
|
||||
parentId: "mac",
|
||||
orderNumber: 90,
|
||||
});
|
||||
|
||||
export const separator4 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-4",
|
||||
parentId: "mac",
|
||||
orderNumber: 130,
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 productNameInjectable from "../../../../../../common/vars/product-name.injectable";
|
||||
import showAboutInjectable from "./show-about.injectable";
|
||||
import applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const aboutMenuItemInjectable = getInjectable({
|
||||
id: "about-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const productName = di.inject(productNameInjectable);
|
||||
const showAbout = di.inject(showAboutInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: "about",
|
||||
parentId: isMac ? "mac" : "help",
|
||||
orderNumber: isMac ? 10 : 40,
|
||||
label: `About ${productName}`,
|
||||
|
||||
onClick() {
|
||||
showAbout();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default aboutMenuItemInjectable;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 showMessagePopupInjectable from "../../../../../../main/electron-app/features/show-message-popup.injectable";
|
||||
import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable";
|
||||
import appNameInjectable from "../../../../../../common/vars/app-name.injectable";
|
||||
import productNameInjectable from "../../../../../../common/vars/product-name.injectable";
|
||||
import buildVersionInjectable from "../../../../../../main/vars/build-version/build-version.injectable";
|
||||
import extensionApiVersionInjectable from "../../../../../../common/vars/extension-api-version.injectable";
|
||||
import applicationCopyrightInjectable from "../../../../../../common/vars/application-copyright.injectable";
|
||||
|
||||
const showAboutInjectable = getInjectable({
|
||||
id: "show-about",
|
||||
|
||||
instantiate: (di) => {
|
||||
const buildVersion = di.inject(buildVersionInjectable);
|
||||
const extensionApiVersion = di.inject(extensionApiVersionInjectable);
|
||||
const showMessagePopup = di.inject(showMessagePopupInjectable);
|
||||
const isWindows = di.inject(isWindowsInjectable);
|
||||
const appName = di.inject(appNameInjectable);
|
||||
const productName = di.inject(productNameInjectable);
|
||||
const applicationCopyright = di.inject(applicationCopyrightInjectable);
|
||||
|
||||
return () => {
|
||||
const appInfo = [
|
||||
`${appName}: ${buildVersion.get()}`,
|
||||
`Extension API: ${extensionApiVersion}`,
|
||||
`Electron: ${process.versions.electron}`,
|
||||
`Chrome: ${process.versions.chrome}`,
|
||||
`Node: ${process.versions.node}`,
|
||||
applicationCopyright,
|
||||
];
|
||||
|
||||
showMessagePopup(
|
||||
`${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
productName,
|
||||
appInfo.join("\r\n"),
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default showAboutInjectable;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { webContents } from "electron";
|
||||
|
||||
const goBackMenuItemInjectable = getInjectable({
|
||||
id: "go-back-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "go-back",
|
||||
orderNumber: 40,
|
||||
label: "Back",
|
||||
keyboardShortcut: "CmdOrCtrl+[",
|
||||
|
||||
onClick: () => {
|
||||
webContents
|
||||
.getAllWebContents()
|
||||
.filter((wc) => wc.getType() === "window")
|
||||
.forEach((wc) => wc.goBack());
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default goBackMenuItemInjectable;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { webContents } from "electron";
|
||||
|
||||
const goForwardMenuItemInjectable = getInjectable({
|
||||
id: "go-forward-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "go-forward",
|
||||
orderNumber: 50,
|
||||
label: "Forward",
|
||||
keyboardShortcut: "CmdOrCtrl+]",
|
||||
|
||||
onClick: () => {
|
||||
webContents
|
||||
.getAllWebContents()
|
||||
.filter((wc) => wc.getType() === "window")
|
||||
.forEach((wc) => wc.goForward());
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default goForwardMenuItemInjectable;
|
||||
+32
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToCatalogInjectable from "../../../../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
|
||||
const navigateToCatalogMenuItemInjectable = getInjectable({
|
||||
id: "navigate-to-catalog-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToCatalog = di.inject(navigateToCatalogInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "navigate-to-catalog",
|
||||
orderNumber: 10,
|
||||
label: "Catalog",
|
||||
keyboardShortcut: "Shift+CmdOrCtrl+C",
|
||||
|
||||
onClick: () => {
|
||||
navigateToCatalog();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToCatalogMenuItemInjectable;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import broadcastMessageInjectable from "../../../../../../common/ipc/broadcast-message.injectable";
|
||||
|
||||
const openCommandPaletteMenuItemInjectable = getInjectable({
|
||||
id: "open-command-palette-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const broadcastMessage = di.inject(broadcastMessageInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "open-command-palette",
|
||||
orderNumber: 20,
|
||||
label: "Command Palette...",
|
||||
keyboardShortcut: "Shift+CmdOrCtrl+P",
|
||||
|
||||
onClick(_m, _b, event) {
|
||||
/**
|
||||
* Don't broadcast unless it was triggered by menu iteration so that
|
||||
* there aren't double events in renderer
|
||||
*
|
||||
* NOTE: this `?` is required because of a bug in playwright. https://github.com/microsoft/playwright/issues/10554
|
||||
*/
|
||||
if (!event?.triggeredByAccelerator) {
|
||||
broadcastMessage("command-palette:open");
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openCommandPaletteMenuItemInjectable;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import {
|
||||
getApplicationMenuOperationSystemActionInjectable,
|
||||
} from "../../get-application-menu-operation-system-action-injectable";
|
||||
|
||||
export const actionForToggleDevTools = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "toggle-dev-tools",
|
||||
parentId: "view",
|
||||
orderNumber: 70,
|
||||
actionName: "toggleDevTools",
|
||||
});
|
||||
|
||||
export const actionForResetZoom = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "reset-zoom",
|
||||
parentId: "view",
|
||||
orderNumber: 90,
|
||||
actionName: "resetZoom",
|
||||
});
|
||||
|
||||
export const actionForZoomIn = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "zoom-in",
|
||||
parentId: "view",
|
||||
orderNumber: 100,
|
||||
actionName: "zoomIn",
|
||||
});
|
||||
|
||||
export const actionForZoomOut = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "zoom-out",
|
||||
parentId: "view",
|
||||
orderNumber: 110,
|
||||
actionName: "zoomOut",
|
||||
});
|
||||
|
||||
export const actionForToggleFullScreen = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "toggle-full-screen",
|
||||
parentId: "view",
|
||||
orderNumber: 130,
|
||||
actionName: "togglefullscreen",
|
||||
});
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import reloadCurrentApplicationWindowInjectable from "../../../../../../main/start-main-application/lens-window/reload-current-application-window.injectable";
|
||||
|
||||
const reloadMenuItemInjectable = getInjectable({
|
||||
id: "reload-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const reloadApplicationWindow = di.inject(
|
||||
reloadCurrentApplicationWindowInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "reload",
|
||||
orderNumber: 60,
|
||||
label: "Reload",
|
||||
keyboardShortcut: "CmdOrCtrl+R",
|
||||
|
||||
onClick: () => {
|
||||
reloadApplicationWindow();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default reloadMenuItemInjectable;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 80,
|
||||
});
|
||||
|
||||
export const separator3 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-3-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 120,
|
||||
});
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const viewMenuItemInjectable = getInjectable({
|
||||
id: "view-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
parentId: "root" as const,
|
||||
id: "view",
|
||||
orderNumber: 40,
|
||||
label: "View",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default viewMenuItemInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { MenuItemConstructorOptions } from "electron";
|
||||
import type { IComputedValue } from "mobx";
|
||||
|
||||
export type MenuRegistration = {
|
||||
parentId: string;
|
||||
visible?: IComputedValue<boolean> | boolean;
|
||||
} & Omit<MenuItemConstructorOptions, "visible">;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { Menu } from "electron";
|
||||
import type { MenuItemOpts } from "./application-menu-items.injectable";
|
||||
|
||||
export type MenuTopId = "mac" | "file" | "edit" | "view" | "help";
|
||||
|
||||
export function buildMenu(applicationMenuItems: MenuItemOpts[]) {
|
||||
Menu.setApplicationMenu(
|
||||
Menu.buildFromTemplate(applicationMenuItems),
|
||||
);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import populateApplicationMenuInjectable from "./populate-application-menu.injectable";
|
||||
import { getGlobalOverride } from "../../../common/test-utils/get-global-override";
|
||||
|
||||
export default getGlobalOverride(populateApplicationMenuInjectable, () => () => {});
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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 { Menu } from "electron";
|
||||
import type { MenuItemOpts } from "./application-menu-items.injectable";
|
||||
import type { Composite } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import type { ApplicationMenuItemTypes } from "./menu-items/application-menu-item-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { map, sortBy } from "lodash/fp";
|
||||
import type { MenuItemRoot } from "./application-menu-item-composite.injectable";
|
||||
import { checkThatAllDiscriminablesAreExhausted } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
|
||||
const populateApplicationMenuInjectable = getInjectable({
|
||||
id: "populate-application-menu",
|
||||
|
||||
instantiate:
|
||||
() => (composite: Composite<ApplicationMenuItemTypes | MenuItemRoot>) => {
|
||||
const electronTemplate = getApplicationMenuTemplate(composite);
|
||||
const menu = Menu.buildFromTemplate(electronTemplate);
|
||||
|
||||
Menu.setApplicationMenu(menu);
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default populateApplicationMenuInjectable;
|
||||
|
||||
export const getApplicationMenuTemplate = (composite: Composite<ApplicationMenuItemTypes | MenuItemRoot>) => {
|
||||
const topLevelMenus = composite.children.filter(
|
||||
(x): x is Composite<ApplicationMenuItemTypes> => x.value.kind !== "root",
|
||||
);
|
||||
|
||||
return topLevelMenus.map(toHierarchicalElectronMenuItem);
|
||||
};
|
||||
|
||||
const toHierarchicalElectronMenuItem = (
|
||||
composite: Composite<ApplicationMenuItemTypes>,
|
||||
): MenuItemOpts => {
|
||||
const value = composite.value;
|
||||
|
||||
switch (value.kind) {
|
||||
case "top-level-menu": {
|
||||
const { id } = composite;
|
||||
const { label, role } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
...(role ? { role } : {}),
|
||||
label,
|
||||
|
||||
submenu: pipeline(
|
||||
composite.children,
|
||||
sortBy((childComposite) => childComposite.value.orderNumber),
|
||||
map(toHierarchicalElectronMenuItem),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
case "sub-menu": {
|
||||
const { id } = composite;
|
||||
const { label } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
label,
|
||||
|
||||
submenu: pipeline(
|
||||
composite.children,
|
||||
sortBy((childComposite) => childComposite.value.orderNumber),
|
||||
map(toHierarchicalElectronMenuItem),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
case "clickable-menu-item": {
|
||||
const { id } = composite;
|
||||
const { label, onClick, keyboardShortcut } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
...(label ? { label } : {}),
|
||||
...(keyboardShortcut ? { accelerator: keyboardShortcut }: {}),
|
||||
click: onClick,
|
||||
};
|
||||
}
|
||||
|
||||
case "os-action-menu-item": {
|
||||
const { label, keyboardShortcut, actionName } = value;
|
||||
|
||||
return {
|
||||
...(label ? { label } : {}),
|
||||
...(keyboardShortcut ? { accelerator: keyboardShortcut } : {}),
|
||||
role: actionName,
|
||||
};
|
||||
}
|
||||
|
||||
case "separator": {
|
||||
return {
|
||||
type: "separator",
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
throw checkThatAllDiscriminablesAreExhausted(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 applicationMenuReactivityInjectable from "./application-menu-reactivity.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../../../main/start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
|
||||
const startApplicationMenuInjectable = getInjectable({
|
||||
id: "start-application-menu",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenu = di.inject(
|
||||
applicationMenuReactivityInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
id: "start-application-menu",
|
||||
run: () => {
|
||||
applicationMenu.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default startApplicationMenuInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 applicationMenuReactivityInjectable from "./application-menu-reactivity.injectable";
|
||||
import { beforeQuitOfBackEndInjectionToken } from "../../../main/start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
|
||||
|
||||
const stopApplicationMenuInjectable = getInjectable({
|
||||
id: "stop-application-menu",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenu = di.inject(applicationMenuReactivityInjectable);
|
||||
|
||||
return {
|
||||
id: "stop-application-menu",
|
||||
run: () => void applicationMenu.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
});
|
||||
|
||||
export default stopApplicationMenuInjectable;
|
||||
Reference in new issue
Block a user