mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix: remove hotbar name from status bar (#4679)
* Show tooltip with hotbar name manually Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Remove this.refreshPosition() call Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Remove hotbar name from status bar Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Convert HotbarSelector to use css modules Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Remove unused export Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fixing linter Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Clean up Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Invert invisible prop Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Linter fix Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
e862d5bf1d
commit
74d92d09d9
@ -98,9 +98,6 @@ export async function bootstrap(di: DependencyInjectionContainer) {
|
|||||||
logger.info(`${logPrefix} initializing IpcRendererListeners`);
|
logger.info(`${logPrefix} initializing IpcRendererListeners`);
|
||||||
initializers.initIpcRendererListeners(extensionLoader);
|
initializers.initIpcRendererListeners(extensionLoader);
|
||||||
|
|
||||||
logger.info(`${logPrefix} initializing StatusBarRegistry`);
|
|
||||||
initializers.initStatusBarRegistry();
|
|
||||||
|
|
||||||
extensionLoader.init();
|
extensionLoader.init();
|
||||||
|
|
||||||
const extensionDiscovery = di.inject(extensionDiscoveryInjectable);
|
const extensionDiscovery = di.inject(extensionDiscoveryInjectable);
|
||||||
|
|||||||
@ -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) => (
|
|
||||||
<div
|
|
||||||
className="flex items-center"
|
|
||||||
data-testid="current-hotbar-name"
|
|
||||||
onClick={() => openCommandOverlay(<HotbarSwitchCommand />)}
|
|
||||||
>
|
|
||||||
<Icon material="bookmarks" className="mr-2" size={14} />
|
|
||||||
{activeHotbarName()}
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
|
|
||||||
export const ActiveHotbarName = withInjectables<Dependencies>(NonInjectedActiveHotbarName, {
|
|
||||||
getProps: (di, props) => ({
|
|
||||||
activeHotbarName: () => di.inject(hotbarManagerInjectable).getActive()?.name,
|
|
||||||
openCommandOverlay: di.inject(commandOverlayInjectable).open,
|
|
||||||
...props,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
@ -4,68 +4,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import mockFs from "mock-fs";
|
import { render } from "@testing-library/react";
|
||||||
import { fireEvent } from "@testing-library/react";
|
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
import "@testing-library/jest-dom/extend-expect";
|
||||||
import { BottomBar } from "./bottom-bar";
|
import { BottomBar } from "./bottom-bar";
|
||||||
import { StatusBarRegistry } from "../../../extensions/registries";
|
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", () => ({
|
jest.mock("electron", () => ({
|
||||||
app: {
|
app: {
|
||||||
getName: () => "lens",
|
getPath: () => "/foo",
|
||||||
setName: jest.fn(),
|
|
||||||
setPath: jest.fn(),
|
|
||||||
getPath: () => "tmp",
|
|
||||||
},
|
|
||||||
ipcMain: {
|
|
||||||
handle: jest.fn(),
|
|
||||||
on: jest.fn(),
|
|
||||||
removeAllListeners: jest.fn(),
|
|
||||||
off: jest.fn(),
|
|
||||||
send: jest.fn(),
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const foobarHotbar = getEmptyHotbar("foobar");
|
|
||||||
|
|
||||||
describe("<BottomBar />", () => {
|
describe("<BottomBar />", () => {
|
||||||
let di: DependencyInjectionContainer;
|
beforeEach(() => {
|
||||||
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();
|
|
||||||
|
|
||||||
StatusBarRegistry.createInstance();
|
StatusBarRegistry.createInstance();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
StatusBarRegistry.resetInstance();
|
StatusBarRegistry.resetInstance();
|
||||||
mockFs.restore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders w/o errors", () => {
|
it("renders w/o errors", () => {
|
||||||
@ -111,33 +67,6 @@ describe("<BottomBar />", () => {
|
|||||||
expect(getByTestId(testId)).toHaveTextContent(text);
|
expect(getByTestId(testId)).toHaveTextContent(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows active hotbar name", () => {
|
|
||||||
StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
|
|
||||||
{ item: () => <ActiveHotbarName/> },
|
|
||||||
]);
|
|
||||||
const { getByTestId } = render(<BottomBar />);
|
|
||||||
|
|
||||||
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: () => <ActiveHotbarName/> },
|
|
||||||
]);
|
|
||||||
const { getByTestId } = render(<BottomBar />);
|
|
||||||
const activeHotbar = getByTestId("current-hotbar-name");
|
|
||||||
|
|
||||||
fireEvent.click(activeHotbar);
|
|
||||||
|
|
||||||
|
|
||||||
expect(mockOpen).toHaveBeenCalledWith(<HotbarSwitchCommand />);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sort positioned items properly", () => {
|
it("sort positioned items properly", () => {
|
||||||
StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
|
StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.HotbarSelector {
|
.HotbarSelector {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
background-color: var(--layoutBackground);
|
background-color: var(--layoutBackground);
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -17,7 +19,13 @@
|
|||||||
top: -20px;
|
top: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.SelectorIndex {
|
.HotbarIndex {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Badge {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: var(--secondaryBackground);
|
background: var(--secondaryBackground);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -3,21 +3,18 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./hotbar-selector.scss";
|
import styles from "./hotbar-selector.module.scss";
|
||||||
import React from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import hotbarManagerInjectable from "../../../common/hotbar-store.injectable";
|
import hotbarManagerInjectable from "../../../common/hotbar-store.injectable";
|
||||||
import { HotbarSwitchCommand } from "./hotbar-switch-command";
|
import { HotbarSwitchCommand } from "./hotbar-switch-command";
|
||||||
import { TooltipPosition } from "../tooltip";
|
import { Tooltip, TooltipPosition } from "../tooltip";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import type { Hotbar } from "../../../common/hotbar-types";
|
import type { Hotbar } from "../../../common/hotbar-types";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
||||||
|
import { cssNames } from "../../utils";
|
||||||
export interface HotbarSelectorProps {
|
|
||||||
hotbar: Hotbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
hotbarManager: {
|
hotbarManager: {
|
||||||
@ -29,25 +26,63 @@ interface Dependencies {
|
|||||||
openCommandOverlay: (component: React.ReactElement) => void;
|
openCommandOverlay: (component: React.ReactElement) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedHotbarSelector = observer(({ hotbar, hotbarManager, openCommandOverlay }: HotbarSelectorProps & Dependencies) => (
|
export interface HotbarSelectorProps extends Partial<Dependencies> {
|
||||||
<div className="HotbarSelector flex align-center">
|
hotbar: Hotbar;
|
||||||
<Icon material="play_arrow" className="previous box" onClick={() => hotbarManager.switchToPrevious()} />
|
}
|
||||||
<div className="box grow flex align-center">
|
|
||||||
<Badge
|
const NonInjectedHotbarSelector = observer(({ hotbar, hotbarManager, openCommandOverlay }: HotbarSelectorProps & Dependencies) => {
|
||||||
id="hotbarIndex"
|
const [tooltipVisible, setTooltipVisible] = useState(false);
|
||||||
small
|
const tooltipTimeout = useRef<NodeJS.Timeout>();
|
||||||
label={hotbarManager.getDisplayIndex(hotbarManager.getActive())}
|
|
||||||
onClick={() => openCommandOverlay(<HotbarSwitchCommand />)}
|
function clearTimer() {
|
||||||
tooltip={{
|
clearTimeout(tooltipTimeout.current);
|
||||||
preferredPositions: [TooltipPosition.TOP, TooltipPosition.TOP_LEFT],
|
}
|
||||||
children: hotbar.name,
|
|
||||||
}}
|
function onTooltipShow() {
|
||||||
className="SelectorIndex"
|
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 (
|
||||||
|
<div className={styles.HotbarSelector}>
|
||||||
|
<Icon
|
||||||
|
material="play_arrow"
|
||||||
|
className={cssNames(styles.Icon, styles.previous)}
|
||||||
|
onClick={() => onArrowClick(hotbarManager.switchToPrevious)}
|
||||||
/>
|
/>
|
||||||
|
<div className={styles.HotbarIndex}>
|
||||||
|
<Badge
|
||||||
|
id="hotbarIndex"
|
||||||
|
small
|
||||||
|
label={hotbarManager.getDisplayIndex(hotbarManager.getActive())}
|
||||||
|
onClick={() => openCommandOverlay(<HotbarSwitchCommand />)}
|
||||||
|
className={styles.Badge}
|
||||||
|
onMouseEnter={onMouseEvent}
|
||||||
|
onMouseLeave={onMouseEvent}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
visible={tooltipVisible}
|
||||||
|
targetId="hotbarIndex"
|
||||||
|
preferredPositions={[TooltipPosition.TOP, TooltipPosition.TOP_LEFT]}
|
||||||
|
>
|
||||||
|
{hotbar.name}
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<Icon material="play_arrow" className={styles.Icon} onClick={() => onArrowClick(hotbarManager.switchToNext)} />
|
||||||
</div>
|
</div>
|
||||||
<Icon material="play_arrow" className="next box" onClick={() => hotbarManager.switchToNext()} />
|
);
|
||||||
</div>
|
});
|
||||||
));
|
|
||||||
|
|
||||||
export const HotbarSelector = withInjectables<Dependencies, HotbarSelectorProps>(NonInjectedHotbarSelector, {
|
export const HotbarSelector = withInjectables<Dependencies, HotbarSelectorProps>(NonInjectedHotbarSelector, {
|
||||||
getProps: (di, props) => ({
|
getProps: (di, props) => ({
|
||||||
|
|||||||
@ -25,14 +25,15 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: opacity 150ms 150ms ease-in-out;
|
transition: opacity 150ms 150ms ease-in-out;
|
||||||
z-index: 100000;
|
z-index: 100000;
|
||||||
opacity: 1;
|
|
||||||
box-shadow: 0 8px 16px rgba(0,0,0,0.24);
|
box-shadow: 0 8px 16px rgba(0,0,0,0.24);
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
|
||||||
&.invisible {
|
&.visible {
|
||||||
left: 0;
|
opacity: 1;
|
||||||
top: 0;
|
visibility: visible;
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:empty {
|
&:empty {
|
||||||
|
|||||||
@ -54,7 +54,7 @@ export class Tooltip extends React.Component<TooltipProps> {
|
|||||||
|
|
||||||
@observable.ref elem: HTMLElement;
|
@observable.ref elem: HTMLElement;
|
||||||
@observable activePosition: TooltipPosition;
|
@observable activePosition: TooltipPosition;
|
||||||
@observable isVisible = !!this.props.visible;
|
@observable isVisible = false;
|
||||||
|
|
||||||
constructor(props: TooltipProps) {
|
constructor(props: TooltipProps) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -78,6 +78,10 @@ export class Tooltip extends React.Component<TooltipProps> {
|
|||||||
this.hoverTarget.addEventListener("mouseleave", this.onLeaveTarget);
|
this.hoverTarget.addEventListener("mouseleave", this.onLeaveTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.refreshPosition();
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.hoverTarget.removeEventListener("mouseenter", this.onEnterTarget);
|
this.hoverTarget.removeEventListener("mouseenter", this.onEnterTarget);
|
||||||
this.hoverTarget.removeEventListener("mouseleave", this.onLeaveTarget);
|
this.hoverTarget.removeEventListener("mouseleave", this.onLeaveTarget);
|
||||||
@ -210,9 +214,9 @@ export class Tooltip extends React.Component<TooltipProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
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, {
|
const className = cssNames("Tooltip", this.props.className, formatters, this.activePosition, {
|
||||||
invisible: !this.isVisible,
|
visible: visible ?? this.isVisible,
|
||||||
formatter: !!formatters,
|
formatter: !!formatters,
|
||||||
});
|
});
|
||||||
const tooltip = (
|
const tooltip = (
|
||||||
|
|||||||
@ -12,4 +12,3 @@ export * from "./kube-object-menu-registry";
|
|||||||
export * from "./registries";
|
export * from "./registries";
|
||||||
export * from "./workloads-overview-detail-registry";
|
export * from "./workloads-overview-detail-registry";
|
||||||
export * from "./catalog-category-registry";
|
export * from "./catalog-category-registry";
|
||||||
export * from "./status-bar-registry";
|
|
||||||
|
|||||||
@ -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: () => <ActiveHotbarName/>,
|
|
||||||
position: "left",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user