mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
menu.ts: refactoring and fixes, reuse route paths from views (renderer)
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
117ad584d3
commit
a4bcfc1e52
@ -69,16 +69,24 @@ export function handleIpc(channel: IpcChannel, handler: IpcMessageHandler, optio
|
||||
export interface IpcPairOptions {
|
||||
channel: IpcChannel
|
||||
handle?: IpcMessageHandler
|
||||
options?: IpcHandleOpts
|
||||
autoBind?: boolean;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export function createIpcChannel({ channel, ...initOpts }: IpcPairOptions) {
|
||||
// todo: improve api
|
||||
export function createIpcChannel({ channel, autoBind, ...initOpts }: IpcPairOptions) {
|
||||
const bindHandler = (opts: { handler?: IpcMessageHandler, options?: IpcHandleOpts } = {}) => {
|
||||
const handler = opts.handler || initOpts.handle || Function;
|
||||
const options = opts.options || { timeout: initOpts.timeout };
|
||||
handleIpc(channel, handler, options);
|
||||
};
|
||||
if (autoBind) {
|
||||
bindHandler();
|
||||
}
|
||||
return {
|
||||
handleInMain: (opts: Partial<Omit<IpcPairOptions, "channel">> = {}) => {
|
||||
const { handle = initOpts.handle, options = initOpts.options } = opts;
|
||||
return handleIpc(channel, handle, options);
|
||||
},
|
||||
invokeFromRenderer: (...args: any[]) => {
|
||||
channel: channel,
|
||||
handleInMain: bindHandler,
|
||||
invokeFromRenderer(...args: any[]) {
|
||||
return invokeIpc(channel, ...args);
|
||||
},
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import "../common/prometheus-providers"
|
||||
import { app, dialog } from "electron"
|
||||
import { appName, appProto, staticDir, staticProto } from "../common/vars";
|
||||
import path from "path"
|
||||
import initMenu from "./menu"
|
||||
import { initMenu } from "./menu"
|
||||
import { LensProxy } from "./lens-proxy"
|
||||
import { WindowManager } from "./window-manager";
|
||||
import { ClusterManager } from "./cluster-manager";
|
||||
@ -41,7 +41,6 @@ async function main() {
|
||||
const updater = new AppUpdater()
|
||||
updater.start();
|
||||
|
||||
initMenu();
|
||||
registerFileProtocol(appProto, app.getPath("userData"));
|
||||
registerFileProtocol(staticProto, staticDir);
|
||||
|
||||
@ -76,6 +75,7 @@ async function main() {
|
||||
// create window manager and open app
|
||||
windowManager = new WindowManager(proxyPort);
|
||||
windowManager.showSplash();
|
||||
initMenu(windowManager);
|
||||
}
|
||||
|
||||
app.on("ready", main);
|
||||
|
||||
203
src/main/menu.ts
203
src/main/menu.ts
@ -1,113 +1,71 @@
|
||||
import type { WindowManager } from "./window-manager";
|
||||
import { app, BrowserWindow, dialog, Menu, MenuItem, MenuItemConstructorOptions, shell, webContents } from "electron"
|
||||
import { broadcastIpc } from "../common/ipc";
|
||||
import { appName, isMac, issuesTrackerUrl, isWindows, slackUrl } from "../common/vars";
|
||||
import { clusterStore } from "../common/cluster-store";
|
||||
import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route";
|
||||
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
||||
import { whatsNewURL } from "../renderer/components/+whats-new/whats-new.route";
|
||||
import { clusterSettingsURL } from "../renderer/components/+cluster-settings/cluster-settings.route";
|
||||
|
||||
// todo: refactor + split menu sections to separated files, e.g. menus/file.menu.ts
|
||||
export function initMenu(windowManager: WindowManager) {
|
||||
const menuItems: MenuItemConstructorOptions[] = [];
|
||||
|
||||
export interface MenuOptions {
|
||||
logoutHook: any;
|
||||
addClusterHook: any;
|
||||
clusterSettingsHook: any;
|
||||
showWhatsNewHook: any;
|
||||
showPreferencesHook: any;
|
||||
// all the above are really () => void type functions
|
||||
}
|
||||
function navigate(url: string) {
|
||||
const activeClusterId = clusterStore.activeClusterId;
|
||||
const view = windowManager.getView(activeClusterId);
|
||||
if (view) {
|
||||
broadcastIpc({
|
||||
channel: "menu:navigate",
|
||||
webContentId: view.id,
|
||||
args: [url],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setClusterSettingsEnabled(enabled: boolean) {
|
||||
const menuIndex = isMac ? 1 : 0
|
||||
Menu.getApplicationMenu().items[menuIndex].submenu.items[1].enabled = enabled
|
||||
}
|
||||
function macOnly(menuItems: MenuItemConstructorOptions[]): MenuItemConstructorOptions[] {
|
||||
if (!isMac) return [];
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
export function showAbout(_menuitem: MenuItem, browserWindow: BrowserWindow) {
|
||||
const appInfo = [
|
||||
`${appName}: ${app.getVersion()}`,
|
||||
`Electron: ${process.versions.electron}`,
|
||||
`Chrome: ${process.versions.chrome}`,
|
||||
`Copyright 2020 Lakend Labs, Inc.`,
|
||||
]
|
||||
dialog.showMessageBoxSync(browserWindow, {
|
||||
title: `${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
type: "info",
|
||||
buttons: ["Close"],
|
||||
message: `Lens`,
|
||||
detail: appInfo.join("\r\n")
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the menu based on the example at: https://electronjs.org/docs/api/menu#main-process
|
||||
* Menu items are constructed piece-by-piece to have slightly better control on individual sub-menus
|
||||
*/
|
||||
export default function initMenu(opts: Partial<MenuOptions> = {}) {
|
||||
const mt: MenuItemConstructorOptions[] = [];
|
||||
const macAppMenu: MenuItemConstructorOptions = {
|
||||
label: app.getName(),
|
||||
// "File" submenu
|
||||
menuItems.push({
|
||||
label: isMac ? app.getName() : "File",
|
||||
submenu: [
|
||||
{
|
||||
label: "About Lens",
|
||||
click: showAbout
|
||||
label: 'Add Cluster',
|
||||
click() {
|
||||
navigate(addClusterURL())
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cluster Settings',
|
||||
click() {
|
||||
navigate(clusterSettingsURL())
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Preferences',
|
||||
click: opts.showPreferencesHook,
|
||||
enabled: true
|
||||
click() {
|
||||
navigate(preferencesURL())
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
...macOnly([
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
]),
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
};
|
||||
if (isMac) {
|
||||
mt.push(macAppMenu);
|
||||
}
|
||||
});
|
||||
|
||||
let fileMenu: MenuItemConstructorOptions;
|
||||
if (isMac) {
|
||||
fileMenu = {
|
||||
label: 'File',
|
||||
submenu: [{
|
||||
label: 'Add Cluster...',
|
||||
click: opts.addClusterHook,
|
||||
},
|
||||
{
|
||||
label: 'Cluster Settings',
|
||||
click: opts.clusterSettingsHook,
|
||||
enabled: false
|
||||
}
|
||||
]
|
||||
}
|
||||
} else {
|
||||
fileMenu = {
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Add Cluster...',
|
||||
click: opts.addClusterHook,
|
||||
},
|
||||
{
|
||||
label: 'Cluster Settings',
|
||||
click: opts.clusterSettingsHook,
|
||||
enabled: false
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Preferences',
|
||||
click: opts.showPreferencesHook,
|
||||
enabled: true
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
}
|
||||
}
|
||||
mt.push(fileMenu);
|
||||
|
||||
const editMenu: MenuItemConstructorOptions = {
|
||||
// "Edit" submenu
|
||||
menuItems.push({
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
@ -120,10 +78,10 @@ export default function initMenu(opts: Partial<MenuOptions> = {}) {
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll' },
|
||||
]
|
||||
};
|
||||
mt.push(editMenu);
|
||||
});
|
||||
|
||||
const viewMenu: MenuItemConstructorOptions = {
|
||||
// "View" submenu
|
||||
menuItems.push({
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
@ -155,20 +113,26 @@ export default function initMenu(opts: Partial<MenuOptions> = {}) {
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
};
|
||||
mt.push(viewMenu);
|
||||
})
|
||||
|
||||
const helpMenu: MenuItemConstructorOptions = {
|
||||
// "Help" submenu
|
||||
menuItems.push({
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'License',
|
||||
label: "What's new?",
|
||||
click() {
|
||||
navigate(whatsNewURL())
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "License",
|
||||
click: async () => {
|
||||
shell.openExternal('https://lakendlabs.com/licenses/lens-eula.md');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Community Slack',
|
||||
label: "Community Slack",
|
||||
click: async () => {
|
||||
shell.openExternal(slackUrl);
|
||||
},
|
||||
@ -180,27 +144,26 @@ export default function initMenu(opts: Partial<MenuOptions> = {}) {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "What's new?",
|
||||
click: opts.showWhatsNewHook,
|
||||
},
|
||||
...(!isMac ? [{
|
||||
label: "About Lens",
|
||||
click: showAbout
|
||||
} as MenuItemConstructorOptions] : [])
|
||||
click(menuItem: MenuItem, browserWindow: BrowserWindow) {
|
||||
const appInfo = [
|
||||
`${appName}: ${app.getVersion()}`,
|
||||
`Electron: ${process.versions.electron}`,
|
||||
`Chrome: ${process.versions.chrome}`,
|
||||
`Copyright 2020 Lakend Labs, Inc.`,
|
||||
]
|
||||
dialog.showMessageBoxSync(browserWindow, {
|
||||
title: `${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
type: "info",
|
||||
buttons: ["Close"],
|
||||
message: `Lens`,
|
||||
detail: appInfo.join("\r\n")
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
mt.push(helpMenu);
|
||||
});
|
||||
|
||||
const menu = Menu.buildFromTemplate(mt);
|
||||
const menu = Menu.buildFromTemplate(menuItems);
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
// const promiseIpc = new PromiseIpc({ timeout: 2000 })
|
||||
//
|
||||
// promiseIpc.on("enableClusterSettingsMenuItem", (clusterId: string) => {
|
||||
// setClusterSettingsEnabled(true)
|
||||
// });
|
||||
//
|
||||
// promiseIpc.on("disableClusterSettingsMenuItem", () => {
|
||||
// setClusterSettingsEnabled(false)
|
||||
// });
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ export class WhatsNew extends React.Component {
|
||||
</div>
|
||||
<div className="bottom">
|
||||
<Button
|
||||
primary
|
||||
primary autoFocus
|
||||
label={<Trans>Ok, got it!</Trans>}
|
||||
onClick={this.ok}
|
||||
/>
|
||||
|
||||
@ -5,7 +5,7 @@ import { createPortal } from "react-dom";
|
||||
import { cssNames, noop } from "../../utils";
|
||||
import { Icon } from "../icon";
|
||||
import { Animate, AnimateName } from "../animate";
|
||||
import { browserHistory } from "../../navigation";
|
||||
import { history } from "../../navigation";
|
||||
import { themeStore } from "../../theme.store";
|
||||
|
||||
export interface DrawerProps {
|
||||
@ -36,7 +36,7 @@ export class Drawer extends React.Component<DrawerProps> {
|
||||
private scrollElem: HTMLElement
|
||||
private scrollPos = new Map<string, number>();
|
||||
|
||||
private stopListenLocation = browserHistory.listen(() => {
|
||||
private stopListenLocation = history.listen(() => {
|
||||
this.restoreScrollPos();
|
||||
});
|
||||
|
||||
@ -55,13 +55,13 @@ export class Drawer extends React.Component<DrawerProps> {
|
||||
|
||||
saveScrollPos = () => {
|
||||
if (!this.scrollElem) return;
|
||||
const key = browserHistory.location.key;
|
||||
const key = history.location.key;
|
||||
this.scrollPos.set(key, this.scrollElem.scrollTop);
|
||||
}
|
||||
|
||||
restoreScrollPos = () => {
|
||||
if (!this.scrollElem) return;
|
||||
const key = browserHistory.location.key;
|
||||
const key = history.location.key;
|
||||
this.scrollElem.scrollTop = this.scrollPos.get(key) || 0;
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { userStore } from "../common/user-store";
|
||||
import { workspaceStore } from "../common/workspace-store";
|
||||
import { clusterStore } from "../common/cluster-store";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { browserHistory } from "./navigation";
|
||||
import { history } from "./navigation";
|
||||
import { isMac } from "../common/vars";
|
||||
import { _i18n } from "./i18n";
|
||||
import { ClusterManager } from "./components/cluster-manager";
|
||||
@ -32,7 +32,7 @@ class LensApp extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<I18nProvider i18n={_i18n}>
|
||||
<Router history={browserHistory}>
|
||||
<Router history={history}>
|
||||
<ErrorBoundary>
|
||||
<Switch>
|
||||
{userStore.isNewVersion && <Route component={WhatsNew}/>}
|
||||
|
||||
@ -1,11 +1,19 @@
|
||||
// Navigation helpers
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import { compile } from "path-to-regexp"
|
||||
import { createBrowserHistory, Location, LocationDescriptor } from "history";
|
||||
import { createBrowserHistory, createMemoryHistory, Location, LocationDescriptor } from "history";
|
||||
import { createObservableHistory } from "mobx-observable-history";
|
||||
|
||||
export const browserHistory = createBrowserHistory();
|
||||
export const navigation = createObservableHistory(browserHistory);
|
||||
export const history = typeof window !== "undefined" ? createBrowserHistory() : createMemoryHistory();
|
||||
export const navigation = createObservableHistory(history);
|
||||
|
||||
if (ipcRenderer) {
|
||||
// subscribe for navigation via menu.ts
|
||||
ipcRenderer.on("menu:navigate", (event, path: string) => {
|
||||
navigate(path);
|
||||
});
|
||||
}
|
||||
|
||||
export function navigate(location: LocationDescriptor) {
|
||||
navigation.location = location as Location;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user