From bd082e24ee213672267b047180c80d1b1b7293f4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 1 Feb 2022 17:16:35 -0500 Subject: [PATCH 1/3] Fix StatusBar extension API - Make sure that items are still on right side if no items are registered on left side - Make more injectable Signed-off-by: Sebastian Malton --- src/extensions/common-api/registrations.ts | 2 +- src/extensions/lens-renderer-extension.ts | 2 +- .../bottom-bar-items.injectable.ts | 28 ---- .../cluster-manager/bottom-bar.module.scss | 29 ---- .../cluster-manager/bottom-bar.test.tsx | 151 ------------------ .../components/cluster-manager/bottom-bar.tsx | 74 --------- .../cluster-manager/cluster-manager.scss | 7 +- .../cluster-manager/cluster-manager.tsx | 4 +- .../status-bar-registration.ts | 24 --- .../components/layout/main-layout.module.scss | 2 +- ...registered-status-bar-items.injectable.tsx | 70 ++++++++ .../status-bar/status-bar-items.injectable.ts | 21 +++ .../status-bar/status-bar-registration.ts | 41 +++++ .../status-bar/status-bar.module.scss | 42 +++++ .../components/status-bar/status-bar.test.tsx | 109 +++++++++++++ .../components/status-bar/status-bar.tsx | 49 ++++++ 16 files changed, 338 insertions(+), 317 deletions(-) delete mode 100644 src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts delete mode 100644 src/renderer/components/cluster-manager/bottom-bar.module.scss delete mode 100644 src/renderer/components/cluster-manager/bottom-bar.test.tsx delete mode 100644 src/renderer/components/cluster-manager/bottom-bar.tsx delete mode 100644 src/renderer/components/cluster-manager/status-bar-registration.ts create mode 100644 src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx create mode 100644 src/renderer/components/status-bar/status-bar-items.injectable.ts create mode 100644 src/renderer/components/status-bar/status-bar-registration.ts create mode 100644 src/renderer/components/status-bar/status-bar.module.scss create mode 100644 src/renderer/components/status-bar/status-bar.test.tsx create mode 100644 src/renderer/components/status-bar/status-bar.tsx diff --git a/src/extensions/common-api/registrations.ts b/src/extensions/common-api/registrations.ts index be3e8d87cd4d..794f203036d8 100644 --- a/src/extensions/common-api/registrations.ts +++ b/src/extensions/common-api/registrations.ts @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -export type { StatusBarRegistration } from "../../renderer/components/cluster-manager/status-bar-registration"; +export type { StatusBarRegistration } from "../../renderer/components/status-bar/status-bar-registration"; export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration"; export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration"; export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry"; diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 9d69b4485a6d..b61cd9a2c81c 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -18,7 +18,7 @@ import type { CommandRegistration } from "../renderer/components/command-palette import type { AppPreferenceRegistration } from "../renderer/components/+preferences/app-preferences/app-preference-registration"; import type { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns"; import type { CustomCategoryViewRegistration } from "../renderer/components/+catalog/custom-views"; -import type { StatusBarRegistration } from "../renderer/components/cluster-manager/status-bar-registration"; +import type { StatusBarRegistration } from "../renderer/components/status-bar/status-bar-registration"; import type { KubeObjectMenuRegistration } from "../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration"; export class LensRendererExtension extends LensExtension { diff --git a/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts b/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts deleted file mode 100644 index 9f32831ca6fb..000000000000 --- a/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; -import { computed } from "mobx"; -import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable"; -import type { StatusBarRegistration } from "./status-bar-registration"; - -const bottomBarItemsInjectable = getInjectable({ - instantiate: (di) => { - const extensions = di.inject(rendererExtensionsInjectable); - - return computed(() => - extensions - .get() - .flatMap((extension) => extension.statusBarItems) - .sort(leftItemsBeforeRight), - ); - }, - - lifecycle: lifecycleEnum.singleton, -}); - -export default bottomBarItemsInjectable; - -const leftItemsBeforeRight = (firstItem: StatusBarRegistration, secondItem: StatusBarRegistration) => - firstItem.components?.position?.localeCompare(secondItem.components?.position); diff --git a/src/renderer/components/cluster-manager/bottom-bar.module.scss b/src/renderer/components/cluster-manager/bottom-bar.module.scss deleted file mode 100644 index f6857220d5d2..000000000000 --- a/src/renderer/components/cluster-manager/bottom-bar.module.scss +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -.BottomBar { - @apply flex px-2 text-white; - - grid-area: bottom-bar; - background-color: var(--blue); - height: var(--bottom-bar-height); - font-size: var(--font-size-small); -} - -.item { - @apply flex items-center mr-2 h-full px-2 last:mr-0; - - &:hover { - @apply cursor-pointer; - - background-color: #ffffff33; - } -} - -.onLeft + .onRight { - @apply ml-auto; -} - -.onRight {} diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx deleted file mode 100644 index 523500629c3f..000000000000 --- a/src/renderer/components/cluster-manager/bottom-bar.test.tsx +++ /dev/null @@ -1,151 +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 "@testing-library/jest-dom/extend-expect"; -import { BottomBar } from "./bottom-bar"; -import { getDiForUnitTesting } from "../../getDiForUnitTesting"; -import type { DiRender } from "../test-utils/renderFor"; -import { renderFor } from "../test-utils/renderFor"; -import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import { LensRendererExtension } from "../../../extensions/lens-renderer-extension"; -import { computed, IObservableArray, observable, runInAction } from "mobx"; -import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable"; - -jest.mock("electron", () => ({ - app: { - getPath: () => "/foo", - }, -})); - -class SomeTestExtension extends LensRendererExtension { - constructor(statusBarItems: IObservableArray) { - super({ - id: "some-id", - absolutePath: "irrelevant", - isBundled: false, - isCompatible: false, - isEnabled: false, - manifest: { name: "some-id", version: "some-version" }, - manifestPath: "irrelevant", - }); - - this.statusBarItems = statusBarItems; - } -} - -describe("", () => { - let render: DiRender; - let statusBarItems: IObservableArray; - - beforeEach(async () => { - - statusBarItems = observable.array([]); - - const someTestExtension = new SomeTestExtension(statusBarItems); - - const di = getDiForUnitTesting({ doGeneralOverrides: true }); - - di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data"); - - di.override(rendererExtensionsInjectable, () => { - return computed(() => [someTestExtension]); - }); - - render = renderFor(di); - - await di.runSetups(); - }); - - it("renders w/o errors", () => { - const { container } = render(); - - expect(container).toBeInstanceOf(HTMLElement); - }); - - - it.each([ - undefined, - "hello", - 6, - null, - [], - [{}], - {}, - ])("renders w/o errors when .getItems() returns not type compliant (%p)", val => { - runInAction(() => { - statusBarItems.replace([val]); - }); - - expect(() => render()).not.toThrow(); - }); - - it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", () => { - const testId = "testId"; - const text = "heee"; - - runInAction(() => { - statusBarItems.replace([ - { item: {text} }, - ]); - }); - - const { getByTestId } = render(); - - expect(getByTestId(testId)).toHaveTextContent(text); - }); - - it("renders items [{item: () => React.ReactNode}] (4.0.0-rc.1+)", () => { - const testId = "testId"; - const text = "heee"; - - runInAction(() => { - statusBarItems.replace([ - { item: () => {text} }, - ]); - }); - - const { getByTestId } = render(); - - expect(getByTestId(testId)).toHaveTextContent(text); - }); - - - it("sort positioned items properly", () => { - runInAction(() => { - statusBarItems.replace([ - { - components: { - Item: () =>
right
, - }, - }, - { - components: { - Item: () =>
right
, - position: "right", - }, - }, - { - components: { - Item: () =>
left
, - position: "left", - }, - }, - { - components: { - Item: () =>
left
, - position: "left", - }, - }, - ]); - }); - - const { getAllByTestId } = render(); - const elems = getAllByTestId("sortedElem"); - const positions = elems.map(elem => elem.textContent); - - expect(positions).toEqual(["left", "left", "right", "right"]); - }); -}); diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx deleted file mode 100644 index ecbb1634cce5..000000000000 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import styles from "./bottom-bar.module.scss"; - -import React from "react"; -import { observer } from "mobx-react"; -import { cssNames } from "../../utils"; -import { withInjectables } from "@ogre-tools/injectable-react"; -import bottomBarItemsInjectable from "./bottom-bar-items.injectable"; -import type { IComputedValue } from "mobx"; -import type { StatusBarRegistration } from "./status-bar-registration"; - -interface Dependencies { - items: IComputedValue -} - -@observer -class NonInjectedBottomBar extends React.Component { - renderRegisteredItem(registration: StatusBarRegistration) { - const { item } = registration; - - if (item) { - return typeof item === "function" ? item() : item; - } - - return ; - } - - renderRegisteredItems() { - return ( - <> - {this.props.items.get().map((registration, index) => { - if (!registration?.item && !registration?.components?.Item) { - return null; - } - - return ( -
- {this.renderRegisteredItem(registration)} -
- ); - })} - - ); - } - - render() { - return ( -
- {this.renderRegisteredItems()} -
- ); - } -} - -export const BottomBar = withInjectables( - NonInjectedBottomBar, - - { - getProps: (di, props) => ({ - items: di.inject(bottomBarItemsInjectable), - ...props, - }), - }, -); diff --git a/src/renderer/components/cluster-manager/cluster-manager.scss b/src/renderer/components/cluster-manager/cluster-manager.scss index 0c4230f85092..e6f5bb43e2e2 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.scss +++ b/src/renderer/components/cluster-manager/cluster-manager.scss @@ -4,14 +4,13 @@ */ .ClusterManager { - --bottom-bar-height: 21px; --hotbar-width: 75px; display: grid; grid-template-areas: "topbar topbar" "menu main" - "bottom-bar bottom-bar"; + "status-bar status-bar"; grid-template-rows: auto 1fr min-content; grid-template-columns: min-content 1fr; @@ -26,10 +25,6 @@ grid-area: menu; } - .BottomBar { - grid-area: bottom-bar; - } - #lens-views { position: absolute; left: 0; diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index f7fe8bb40a9c..10e1905a0db0 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -8,7 +8,7 @@ import "./cluster-manager.scss"; import React from "react"; import { Redirect, Route, Switch } from "react-router"; import { disposeOnUnmount, observer } from "mobx-react"; -import { BottomBar } from "./bottom-bar"; +import { StatusBar } from "../status-bar/status-bar"; import { Catalog } from "../+catalog"; import { Preferences } from "../+preferences"; import { AddCluster } from "../+add-cluster"; @@ -71,7 +71,7 @@ class NonInjectedClusterManager extends React.Component { - + ); diff --git a/src/renderer/components/cluster-manager/status-bar-registration.ts b/src/renderer/components/cluster-manager/status-bar-registration.ts deleted file mode 100644 index 2faea55cc511..000000000000 --- a/src/renderer/components/cluster-manager/status-bar-registration.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -interface StatusBarComponents { - Item?: React.ComponentType; - /** - * The side of the bottom bar to place this component. - * - * @default "right" - */ - position?: "left" | "right"; -} - -interface StatusBarRegistrationV2 { - components?: StatusBarComponents; // has to be optional for backwards compatability -} - -export interface StatusBarRegistration extends StatusBarRegistrationV2 { - /** - * @deprecated use components.Item instead - */ - item?: React.ReactNode; -} diff --git a/src/renderer/components/layout/main-layout.module.scss b/src/renderer/components/layout/main-layout.module.scss index 6a8ce8e296f0..fad743041c89 100644 --- a/src/renderer/components/layout/main-layout.module.scss +++ b/src/renderer/components/layout/main-layout.module.scss @@ -25,7 +25,7 @@ .contents { grid-area: contents; overflow: auto; - height: calc(100vh - var(--bottom-bar-height) - var(--main-layout-header)); + height: calc(100vh - var(--status-bar-height) - var(--main-layout-header)); } .footer { diff --git a/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx b/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx new file mode 100644 index 000000000000..701c59b5c962 --- /dev/null +++ b/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx @@ -0,0 +1,70 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import React from "react"; +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import { computed, IComputedValue } from "mobx"; +import type { StatusBarItemProps, StatusBarRegistration } from "./status-bar-registration"; +import statusBarItemsInjectable from "./status-bar-items.injectable"; + +export interface RegisteredStatusBarItems { + right: React.ComponentType[]; + left: React.ComponentType[]; +} + +interface Dependencies { + registrations: IComputedValue; +} + +function getRegisteredStatusBarItems({ registrations }: Dependencies): IComputedValue { + return computed(() => { + const res: RegisteredStatusBarItems = { + left: [], + right: [], + }; + + for (const registration of registrations.get()) { + if (!registration || typeof registration !== "object") { + continue; + } + + if (registration.item) { + const { item } = registration; + + // default for old API is "right" + res.right.push( + () => ( + <> + { + typeof item === "function" + ? item() + : item + } + + ), + ); + } else if (registration.components) { + const { position = "right", Item } = registration.components; + + if (position !== "left" && position !== "right") { + throw new TypeError("StatusBarRegistration.components.position must be either 'right' or 'left'"); + } + + res[position].push(Item); + } + } + + return res; + }); +} + +const registeredStatusBarItemsInjectable = getInjectable({ + instantiate: (di) => getRegisteredStatusBarItems({ + registrations: di.inject(statusBarItemsInjectable), + }), + + lifecycle: lifecycleEnum.singleton, +}); + +export default registeredStatusBarItemsInjectable; diff --git a/src/renderer/components/status-bar/status-bar-items.injectable.ts b/src/renderer/components/status-bar/status-bar-items.injectable.ts new file mode 100644 index 000000000000..33d04cb0fe05 --- /dev/null +++ b/src/renderer/components/status-bar/status-bar-items.injectable.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable"; + +const statusBarItemsInjectable = getInjectable({ + instantiate: (di) => { + const extensions = di.inject(rendererExtensionsInjectable); + + return computed(() => ( + extensions.get() + .flatMap(ext => ext.statusBarItems) + )); + }, + lifecycle: lifecycleEnum.singleton, +}); + +export default statusBarItemsInjectable; diff --git a/src/renderer/components/status-bar/status-bar-registration.ts b/src/renderer/components/status-bar/status-bar-registration.ts new file mode 100644 index 000000000000..8e7219b9536b --- /dev/null +++ b/src/renderer/components/status-bar/status-bar-registration.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +/** + * The props for StatusBar item component + */ +export interface StatusBarItemProps {} + +/** + * The type defining the registration of a status bar item + */ +export interface StatusBarComponents { + /** + * The component for this registrations + */ + Item: React.ComponentType; + + /** + * The side of the bottom bar to place this component. + * + * @default "right" + */ + position?: "left" | "right"; +} + +/** + * The type for registering status bar items from the LensRendererExtension + */ +export interface StatusBarRegistration { + /** + * @deprecated use {@link StatusBarRegistration.components} instead + */ + item?: React.ReactNode | (() => React.ReactNode); + + /** + * The newer API, allows for registering a component instead of a ReactNode + */ + components?: StatusBarComponents; +} diff --git a/src/renderer/components/status-bar/status-bar.module.scss b/src/renderer/components/status-bar/status-bar.module.scss new file mode 100644 index 000000000000..4c1a448529c3 --- /dev/null +++ b/src/renderer/components/status-bar/status-bar.module.scss @@ -0,0 +1,42 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +.StatusBar { + --status-bar-height: 21px; + color: white; + + grid-area: status-bar; + background-color: var(--blue); + height: var(--status-bar-height); + font-size: var(--font-size-small); + + display: inline-grid; + grid-template-columns: 1fr 1fr; +} + +.leftSide { + display: block; + + .item { + float: left; + } +} + +.rightSide { + display: block; + + .item { + float: right; + } +} + +.item { + padding: 2px 4px; + + &:hover { + cursor: pointer; + background-color: #ffffff33; + } +} diff --git a/src/renderer/components/status-bar/status-bar.test.tsx b/src/renderer/components/status-bar/status-bar.test.tsx new file mode 100644 index 000000000000..68f64b5c1439 --- /dev/null +++ b/src/renderer/components/status-bar/status-bar.test.tsx @@ -0,0 +1,109 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { StatusBar } from "./status-bar"; +import { getDiForUnitTesting } from "../../getDiForUnitTesting"; +import type { DiRender } from "../test-utils/renderFor"; +import { renderFor } from "../test-utils/renderFor"; +import { computed } from "mobx"; +import type { ConfigurableDependencyInjectionContainer } from "@ogre-tools/injectable"; +import statusBarItemsInjectable from "./status-bar-items.injectable"; +import type { StatusBarRegistration } from "./status-bar-registration"; + +describe("", () => { + let render: DiRender; + let di: ConfigurableDependencyInjectionContainer; + + beforeEach(async () => { + di = getDiForUnitTesting({ doGeneralOverrides: true }); + render = renderFor(di); + + await di.runSetups(); + }); + + it("renders w/o errors", () => { + di.override(statusBarItemsInjectable, () => computed(() => [] as StatusBarRegistration[])); + const { container } = render(); + + expect(container).toBeInstanceOf(HTMLElement); + }); + + it.each([ + undefined, + "hello", + 6, + null, + [], + [{}], + {}, + ])("renders w/o errors when registrations are not type compliant (%p)", val => { + di.override(statusBarItemsInjectable, () => computed(() => [val] as StatusBarRegistration[])); + + expect(() => render()).not.toThrow(); + }); + + it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", () => { + const testId = "testId"; + const text = "heee"; + + di.override(statusBarItemsInjectable, () => computed(() => [ + { item: {text} }, + ] as StatusBarRegistration[])); + + const { getByTestId } = render(); + + expect(getByTestId(testId)).toHaveTextContent(text); + }); + + it("renders items [{item: () => React.ReactNode}] (4.0.0-rc.1+)", () => { + const testId = "testId"; + const text = "heee"; + + di.override(statusBarItemsInjectable, () => computed(() => [ + { item: () => {text} }, + ] as StatusBarRegistration[])); + + const { getByTestId } = render(); + + expect(getByTestId(testId)).toHaveTextContent(text); + }); + + + it("sort positioned items properly", () => { + di.override(statusBarItemsInjectable, () => computed(() => [ + { + components: { + Item: () =>
right
, + }, + }, + { + components: { + Item: () =>
right
, + position: "right", + }, + }, + { + components: { + Item: () =>
left
, + position: "left", + }, + }, + { + components: { + Item: () =>
left
, + position: "left", + }, + }, + ] as StatusBarRegistration[])); + + const { getAllByTestId } = render(); + const elems = getAllByTestId("sortedElem"); + const positions = elems.map(elem => elem.textContent); + + expect(positions).toEqual(["left", "left", "right", "right"]); + }); +}); diff --git a/src/renderer/components/status-bar/status-bar.tsx b/src/renderer/components/status-bar/status-bar.tsx new file mode 100644 index 000000000000..a9e2f5991bc8 --- /dev/null +++ b/src/renderer/components/status-bar/status-bar.tsx @@ -0,0 +1,49 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import styles from "./status-bar.module.scss"; + +import React from "react"; +import { observer } from "mobx-react"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import registeredStatusBarItemsInjectable, { RegisteredStatusBarItems } from "./registered-status-bar-items.injectable"; +import type { IComputedValue } from "mobx"; + +export interface StatusBarProps {} + +interface Dependencies { + items: IComputedValue +} + +const NonInjectedStatusBar = observer(({ items }: Dependencies & StatusBarProps) => { + const { left, right } = items.get(); + + return ( +
+
+ {left.map((Item, index) => ( +
+ +
+ ))} +
+
+ {right.map((Item, index) => ( +
+ +
+ ))} +
+
+ ); + +}); + +export const StatusBar = withInjectables(NonInjectedStatusBar, { + getProps: (di, props) => ({ + items: di.inject(registeredStatusBarItemsInjectable), + ...props, + }), +}); From 56f2cb9663bd54daf300dc893118582594bc8169 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 9 Feb 2022 11:42:34 -0500 Subject: [PATCH 2/3] Make tests more robust Signed-off-by: Sebastian Malton --- ...registered-status-bar-items.injectable.tsx | 3 ++ .../components/status-bar/status-bar.test.tsx | 49 ++++++++++++++----- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx b/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx index 701c59b5c962..b99edba382e2 100644 --- a/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx +++ b/src/renderer/components/status-bar/registered-status-bar-items.injectable.tsx @@ -55,6 +55,9 @@ function getRegisteredStatusBarItems({ registrations }: Dependencies): IComputed } } + // This is done so that the first ones registered are closest to the corner + res.right.reverse(); + return res; }); } diff --git a/src/renderer/components/status-bar/status-bar.test.tsx b/src/renderer/components/status-bar/status-bar.test.tsx index 68f64b5c1439..6055edf403d5 100644 --- a/src/renderer/components/status-bar/status-bar.test.tsx +++ b/src/renderer/components/status-bar/status-bar.test.tsx @@ -9,24 +9,47 @@ import { StatusBar } from "./status-bar"; import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import type { DiRender } from "../test-utils/renderFor"; import { renderFor } from "../test-utils/renderFor"; -import { computed } from "mobx"; +import { computed, IObservableArray, observable } from "mobx"; import type { ConfigurableDependencyInjectionContainer } from "@ogre-tools/injectable"; import statusBarItemsInjectable from "./status-bar-items.injectable"; import type { StatusBarRegistration } from "./status-bar-registration"; +import { LensRendererExtension } from "../../../extensions/lens-renderer-extension"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable"; + +class SomeTestExtension extends LensRendererExtension { + constructor(statusBarItems: IObservableArray) { + super({ + id: "some-id", + absolutePath: "irrelevant", + isBundled: false, + isCompatible: false, + isEnabled: false, + manifest: { name: "some-id", version: "some-version" }, + manifestPath: "irrelevant", + }); + + this.statusBarItems = statusBarItems; + } +} describe("", () => { let render: DiRender; let di: ConfigurableDependencyInjectionContainer; + let statusBarItems: IObservableArray; beforeEach(async () => { + statusBarItems = observable.array([]); di = getDiForUnitTesting({ doGeneralOverrides: true }); render = renderFor(di); + di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data"); + di.override(rendererExtensionsInjectable, () => computed(() => [new SomeTestExtension(statusBarItems)])); + await di.runSetups(); }); it("renders w/o errors", () => { - di.override(statusBarItemsInjectable, () => computed(() => [] as StatusBarRegistration[])); const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); @@ -41,7 +64,7 @@ describe("", () => { [{}], {}, ])("renders w/o errors when registrations are not type compliant (%p)", val => { - di.override(statusBarItemsInjectable, () => computed(() => [val] as StatusBarRegistration[])); + statusBarItems.replace([val]); expect(() => render()).not.toThrow(); }); @@ -63,9 +86,9 @@ describe("", () => { const testId = "testId"; const text = "heee"; - di.override(statusBarItemsInjectable, () => computed(() => [ - { item: () => {text} }, - ] as StatusBarRegistration[])); + statusBarItems.replace([{ + item: () => {text}, + }]); const { getByTestId } = render(); @@ -74,36 +97,36 @@ describe("", () => { it("sort positioned items properly", () => { - di.override(statusBarItemsInjectable, () => computed(() => [ + statusBarItems.replace([ { components: { - Item: () =>
right
, + Item: () =>
right1
, }, }, { components: { - Item: () =>
right
, + Item: () =>
right2
, position: "right", }, }, { components: { - Item: () =>
left
, + Item: () =>
left1
, position: "left", }, }, { components: { - Item: () =>
left
, + Item: () =>
left2
, position: "left", }, }, - ] as StatusBarRegistration[])); + ]); const { getAllByTestId } = render(); const elems = getAllByTestId("sortedElem"); const positions = elems.map(elem => elem.textContent); - expect(positions).toEqual(["left", "left", "right", "right"]); + expect(positions).toEqual(["left1", "left2", "right2", "right1"]); }); }); From 709e9517ba19ae27427c3a490b4b28176b96d151 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Thu, 10 Feb 2022 07:52:58 +0300 Subject: [PATCH 3/3] Fixing status bar styles Signed-off-by: Alex Andreev --- .../status-bar/status-bar.module.scss | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/renderer/components/status-bar/status-bar.module.scss b/src/renderer/components/status-bar/status-bar.module.scss index 4c1a448529c3..04f07fa31b50 100644 --- a/src/renderer/components/status-bar/status-bar.module.scss +++ b/src/renderer/components/status-bar/status-bar.module.scss @@ -17,23 +17,21 @@ } .leftSide { - display: block; - - .item { - float: left; - } + display: flex; + align-items: center; } .rightSide { - display: block; - - .item { - float: right; - } + display: flex; + align-items: center; + justify-content: flex-end; } .item { - padding: 2px 4px; + height: 100%; + padding: 0 4px; + display: flex; + align-items: center; &:hover { cursor: pointer;