From 74d92d09d9da58a012f8973e940ba979e9e5d148 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Wed, 19 Jan 2022 14:31:15 +0300 Subject: [PATCH] Fix: remove hotbar name from status bar (#4679) * Show tooltip with hotbar name manually Signed-off-by: Alex Andreev * Remove this.refreshPosition() call Signed-off-by: Alex Andreev * Remove hotbar name from status bar Signed-off-by: Alex Andreev * Convert HotbarSelector to use css modules Signed-off-by: Alex Andreev * Remove unused export Signed-off-by: Alex Andreev * Fixing linter Signed-off-by: Alex Andreev * Clean up Signed-off-by: Alex Andreev * Invert invisible prop Signed-off-by: Alex Andreev * Linter fix Signed-off-by: Alex Andreev --- src/renderer/bootstrap.tsx | 3 - .../cluster-manager/active-hotbar-name.tsx | 36 -------- .../cluster-manager/bottom-bar.test.tsx | 77 +---------------- ...ector.scss => hotbar-selector.module.scss} | 10 ++- .../components/hotbar/hotbar-selector.tsx | 83 +++++++++++++------ src/renderer/components/tooltip/tooltip.scss | 13 +-- src/renderer/components/tooltip/tooltip.tsx | 10 ++- src/renderer/initializers/index.ts | 1 - .../initializers/status-bar-registry.tsx | 19 ----- 9 files changed, 85 insertions(+), 167 deletions(-) delete mode 100644 src/renderer/components/cluster-manager/active-hotbar-name.tsx rename src/renderer/components/hotbar/{hotbar-selector.scss => hotbar-selector.module.scss} (85%) delete mode 100644 src/renderer/initializers/status-bar-registry.tsx diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 81f4a52e45..9be509ab61 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -98,9 +98,6 @@ export async function bootstrap(di: DependencyInjectionContainer) { logger.info(`${logPrefix} initializing IpcRendererListeners`); initializers.initIpcRendererListeners(extensionLoader); - logger.info(`${logPrefix} initializing StatusBarRegistry`); - initializers.initStatusBarRegistry(); - extensionLoader.init(); const extensionDiscovery = di.inject(extensionDiscoveryInjectable); diff --git a/src/renderer/components/cluster-manager/active-hotbar-name.tsx b/src/renderer/components/cluster-manager/active-hotbar-name.tsx deleted file mode 100644 index 191a30957e..0000000000 --- a/src/renderer/components/cluster-manager/active-hotbar-name.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import React from "react"; -import { observer } from "mobx-react"; -import { Icon } from "../icon"; -import hotbarManagerInjectable from "../../../common/hotbar-store.injectable"; -import { HotbarSwitchCommand } from "../hotbar/hotbar-switch-command"; -import { withInjectables } from "@ogre-tools/injectable-react"; -import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; - -interface Dependencies { - openCommandOverlay: (component: React.ReactElement) => void; - activeHotbarName: () => string | undefined; -} - -const NonInjectedActiveHotbarName = observer(({ openCommandOverlay, activeHotbarName }: Dependencies) => ( -
openCommandOverlay()} - > - - {activeHotbarName()} -
-)); - -export const ActiveHotbarName = withInjectables(NonInjectedActiveHotbarName, { - getProps: (di, props) => ({ - activeHotbarName: () => di.inject(hotbarManagerInjectable).getActive()?.name, - openCommandOverlay: di.inject(commandOverlayInjectable).open, - ...props, - }), -}); diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx index dcad07d592..97539f0ea3 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.test.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.test.tsx @@ -4,68 +4,24 @@ */ import React from "react"; -import mockFs from "mock-fs"; -import { fireEvent } from "@testing-library/react"; +import { render } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { BottomBar } from "./bottom-bar"; import { StatusBarRegistry } from "../../../extensions/registries"; -import hotbarManagerInjectable from "../../../common/hotbar-store.injectable"; -import { HotbarSwitchCommand } from "../hotbar/hotbar-switch-command"; -import { ActiveHotbarName } from "./active-hotbar-name"; -import { getDiForUnitTesting } from "../../getDiForUnitTesting"; -import { DiRender, renderFor } from "../test-utils/renderFor"; -import type { DependencyInjectionContainer } from "@ogre-tools/injectable"; -import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; -import { getEmptyHotbar } from "../../../common/hotbar-types"; - jest.mock("electron", () => ({ app: { - getName: () => "lens", - setName: jest.fn(), - setPath: jest.fn(), - getPath: () => "tmp", - }, - ipcMain: { - handle: jest.fn(), - on: jest.fn(), - removeAllListeners: jest.fn(), - off: jest.fn(), - send: jest.fn(), + getPath: () => "/foo", }, })); -const foobarHotbar = getEmptyHotbar("foobar"); - describe("", () => { - let di: DependencyInjectionContainer; - let render: DiRender; - - beforeEach(async () => { - const mockOpts = { - "tmp": { - "test-store.json": JSON.stringify({}), - }, - }; - - di = getDiForUnitTesting({ doGeneralOverrides: true }); - - mockFs(mockOpts); - - render = renderFor(di); - - di.override(hotbarManagerInjectable, () => ({ - getActive: () => foobarHotbar, - } as any)); - - await di.runSetups(); - + beforeEach(() => { StatusBarRegistry.createInstance(); }); afterEach(() => { StatusBarRegistry.resetInstance(); - mockFs.restore(); }); it("renders w/o errors", () => { @@ -111,33 +67,6 @@ describe("", () => { expect(getByTestId(testId)).toHaveTextContent(text); }); - it("shows active hotbar name", () => { - StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ - { item: () => }, - ]); - const { getByTestId } = render(); - - expect(getByTestId("current-hotbar-name")).toHaveTextContent("foobar"); - }); - - it("opens command palette on click", () => { - const mockOpen = jest.fn(); - - di.override(commandOverlayInjectable, () => ({ - open: mockOpen, - }) as any); - - StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ - { item: () => }, - ]); - const { getByTestId } = render(); - const activeHotbar = getByTestId("current-hotbar-name"); - - fireEvent.click(activeHotbar); - - - expect(mockOpen).toHaveBeenCalledWith(); - }); it("sort positioned items properly", () => { StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ diff --git a/src/renderer/components/hotbar/hotbar-selector.scss b/src/renderer/components/hotbar/hotbar-selector.module.scss similarity index 85% rename from src/renderer/components/hotbar/hotbar-selector.scss rename to src/renderer/components/hotbar/hotbar-selector.module.scss index 711486ba49..b95823f7fe 100644 --- a/src/renderer/components/hotbar/hotbar-selector.scss +++ b/src/renderer/components/hotbar/hotbar-selector.module.scss @@ -4,6 +4,8 @@ */ .HotbarSelector { + display: flex; + align-items: center; height: 26px; background-color: var(--layoutBackground); position: relative; @@ -17,7 +19,13 @@ top: -20px; } - .SelectorIndex { + .HotbarIndex { + display: flex; + flex-grow: 1; + align-items: center; + } + + .Badge { cursor: pointer; background: var(--secondaryBackground); width: 100%; diff --git a/src/renderer/components/hotbar/hotbar-selector.tsx b/src/renderer/components/hotbar/hotbar-selector.tsx index 3922108ddc..68a8f0e81b 100644 --- a/src/renderer/components/hotbar/hotbar-selector.tsx +++ b/src/renderer/components/hotbar/hotbar-selector.tsx @@ -3,21 +3,18 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import "./hotbar-selector.scss"; -import React from "react"; +import styles from "./hotbar-selector.module.scss"; +import React, { useRef, useState } from "react"; import { Icon } from "../icon"; import { Badge } from "../badge"; import hotbarManagerInjectable from "../../../common/hotbar-store.injectable"; import { HotbarSwitchCommand } from "./hotbar-switch-command"; -import { TooltipPosition } from "../tooltip"; +import { Tooltip, TooltipPosition } from "../tooltip"; import { observer } from "mobx-react"; import type { Hotbar } from "../../../common/hotbar-types"; import { withInjectables } from "@ogre-tools/injectable-react"; import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; - -export interface HotbarSelectorProps { - hotbar: Hotbar; -} +import { cssNames } from "../../utils"; interface Dependencies { hotbarManager: { @@ -29,25 +26,63 @@ interface Dependencies { openCommandOverlay: (component: React.ReactElement) => void; } -const NonInjectedHotbarSelector = observer(({ hotbar, hotbarManager, openCommandOverlay }: HotbarSelectorProps & Dependencies) => ( -
- hotbarManager.switchToPrevious()} /> -
- openCommandOverlay()} - tooltip={{ - preferredPositions: [TooltipPosition.TOP, TooltipPosition.TOP_LEFT], - children: hotbar.name, - }} - className="SelectorIndex" +export interface HotbarSelectorProps extends Partial { + hotbar: Hotbar; +} + +const NonInjectedHotbarSelector = observer(({ hotbar, hotbarManager, openCommandOverlay }: HotbarSelectorProps & Dependencies) => { + const [tooltipVisible, setTooltipVisible] = useState(false); + const tooltipTimeout = useRef(); + + function clearTimer() { + clearTimeout(tooltipTimeout.current); + } + + function onTooltipShow() { + setTooltipVisible(true); + clearTimer(); + tooltipTimeout.current = setTimeout(() => setTooltipVisible(false), 1500); + } + + function onArrowClick(switchTo: () => void) { + onTooltipShow(); + switchTo(); + } + + function onMouseEvent(event: React.MouseEvent) { + clearTimer(); + setTooltipVisible(event.type == "mouseenter"); + } + + return ( +
+ onArrowClick(hotbarManager.switchToPrevious)} /> +
+ openCommandOverlay()} + className={styles.Badge} + onMouseEnter={onMouseEvent} + onMouseLeave={onMouseEvent} + /> + + {hotbar.name} + +
+ onArrowClick(hotbarManager.switchToNext)} />
- hotbarManager.switchToNext()} /> -
-)); + ); +}); export const HotbarSelector = withInjectables(NonInjectedHotbarSelector, { getProps: (di, props) => ({ diff --git a/src/renderer/components/tooltip/tooltip.scss b/src/renderer/components/tooltip/tooltip.scss index 8747cbf2c6..10b7669679 100644 --- a/src/renderer/components/tooltip/tooltip.scss +++ b/src/renderer/components/tooltip/tooltip.scss @@ -25,14 +25,15 @@ pointer-events: none; transition: opacity 150ms 150ms ease-in-out; z-index: 100000; - opacity: 1; box-shadow: 0 8px 16px rgba(0,0,0,0.24); + left: 0; + top: 0; + opacity: 0; + visibility: hidden; - &.invisible { - left: 0; - top: 0; - opacity: 0; - visibility: hidden; + &.visible { + opacity: 1; + visibility: visible; } &:empty { diff --git a/src/renderer/components/tooltip/tooltip.tsx b/src/renderer/components/tooltip/tooltip.tsx index cf0811b7a6..3e35c837a5 100644 --- a/src/renderer/components/tooltip/tooltip.tsx +++ b/src/renderer/components/tooltip/tooltip.tsx @@ -54,7 +54,7 @@ export class Tooltip extends React.Component { @observable.ref elem: HTMLElement; @observable activePosition: TooltipPosition; - @observable isVisible = !!this.props.visible; + @observable isVisible = false; constructor(props: TooltipProps) { super(props); @@ -78,6 +78,10 @@ export class Tooltip extends React.Component { this.hoverTarget.addEventListener("mouseleave", this.onLeaveTarget); } + componentDidUpdate() { + this.refreshPosition(); + } + componentWillUnmount() { this.hoverTarget.removeEventListener("mouseenter", this.onEnterTarget); this.hoverTarget.removeEventListener("mouseleave", this.onLeaveTarget); @@ -210,9 +214,9 @@ export class Tooltip extends React.Component { } render() { - const { style, formatters, usePortal, children } = this.props; + const { style, formatters, usePortal, children, visible } = this.props; const className = cssNames("Tooltip", this.props.className, formatters, this.activePosition, { - invisible: !this.isVisible, + visible: visible ?? this.isVisible, formatter: !!formatters, }); const tooltip = ( diff --git a/src/renderer/initializers/index.ts b/src/renderer/initializers/index.ts index 27fd3bcd6e..3965d45fcf 100644 --- a/src/renderer/initializers/index.ts +++ b/src/renderer/initializers/index.ts @@ -12,4 +12,3 @@ export * from "./kube-object-menu-registry"; export * from "./registries"; export * from "./workloads-overview-detail-registry"; export * from "./catalog-category-registry"; -export * from "./status-bar-registry"; diff --git a/src/renderer/initializers/status-bar-registry.tsx b/src/renderer/initializers/status-bar-registry.tsx deleted file mode 100644 index c0a255a610..0000000000 --- a/src/renderer/initializers/status-bar-registry.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import React from "react"; -import { StatusBarRegistry } from "../../extensions/registries"; -import { ActiveHotbarName } from "../components/cluster-manager/active-hotbar-name"; - -export function initStatusBarRegistry() { - StatusBarRegistry.getInstance().add([ - { - components: { - Item: () => , - position: "left", - }, - }, - ]); -}