1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

auto-update notifications on the status bar (#5361)

* auto-update notifications on the status bar

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* integrated with new and improved autoupdate code

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* lint

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* refactored to include AutoUpdateComponent in the statusBarItemsInjectable

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* refactor to use a registrator

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* fix lint, remove unused code

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* refactored for the simplified logic for injecting many instances PR

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* using the update syncBox injectables directly for status bar notifications

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* removed update broadcasting/listening, updated snapshots

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* fixing tests

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* fixed tests

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* cleanup after rebase to master

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* address review comments

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* fixed incorrect injectable id

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* address review comments

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* Tweak code-style

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Jim Ehrismann 2022-07-01 07:09:00 -04:00 committed by GitHub
parent 165bf57380
commit 3480b517c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1999 additions and 792 deletions

View File

@ -52,9 +52,21 @@ exports[`extension special characters in page registrations renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`extension special characters in page registrations when navigating to r
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>

View File

@ -52,9 +52,21 @@ exports[`navigate to extension page renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`navigate to extension page when extension navigates to child route rend
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
@ -181,9 +205,21 @@ exports[`navigate to extension page when extension navigates to route with param
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
@ -263,9 +299,21 @@ exports[`navigate to extension page when extension navigates to route without pa
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
@ -345,9 +393,21 @@ exports[`navigate to extension page when extension navigates to route without pa
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>

View File

@ -52,9 +52,21 @@ exports[`navigating between routes given route with optional path parameters whe
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<pre>
@ -121,9 +133,21 @@ exports[`navigating between routes given route without path parameters when navi
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>

View File

@ -52,9 +52,21 @@ exports[`add-cluster - navigation using application menu renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`add-cluster - navigation using application menu when navigating to add
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`encourage user to update when sufficient time passed since update was d
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`installing update using tray when started renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -118,55 +130,29 @@ exports[`installing update using tray when started when user checks for updates
>
<div
class="leftSide"
data-testid="status-bar-left"
>
<div
class="item"
>
<div
class="Spinner singleColor"
/>
<div
data-testid="app-update-checking"
>
Checking for updates...
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="Notifications flex column align-flex-end"
>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Checking for updates...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_43"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
</div>
/>
</div>
</body>
`;
@ -224,95 +210,29 @@ exports[`installing update using tray when started when user checks for updates
>
<div
class="leftSide"
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-downloading"
>
Downloading version some-version...
</div>
<div
class="Spinner singleColor"
/>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="Notifications flex column align-flex-end"
>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Checking for updates...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_181"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Download for version some-version started...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_184"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
</div>
/>
</div>
</body>
`;
@ -388,135 +308,26 @@ exports[`installing update using tray when started when user checks for updates
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-download-failed"
>
Download of update failed
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="Notifications flex column align-flex-end"
>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Checking for updates...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_268"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Download for version some-version started...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_271"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Download of update failed
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_277"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
</div>
/>
</div>
</body>
`;
@ -592,95 +403,26 @@ exports[`installing update using tray when started when user checks for updates
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-available"
>
some-version is available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="Notifications flex column align-flex-end"
>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Checking for updates...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_335"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Download for version some-version started...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_338"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
</div>
/>
</div>
</body>
`;
@ -738,95 +480,26 @@ exports[`installing update using tray when started when user checks for updates
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="Notifications flex column align-flex-end"
>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
Checking for updates...
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_104"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
<div
class="Animate opacity notification flex info enter"
style="--enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="box"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="info_outline"
>
info_outline
</span>
</i>
</div>
<div
class="message box grow"
>
No new updates available
</div>
<div
class="box"
>
<i
class="Icon close material interactive focusable"
data-testid="close-notification-for-notification_107"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
</div>
</div>
/>
</div>
</body>
`;

View File

@ -53,9 +53,21 @@ exports[`installing update when started renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -118,9 +130,24 @@ exports[`installing update when started when user checks for updates renders 1`]
>
<div
class="leftSide"
data-testid="status-bar-left"
>
<div
class="item"
>
<div
class="Spinner singleColor"
/>
<div
data-testid="app-update-checking"
>
Checking for updates...
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -183,9 +210,24 @@ exports[`installing update when started when user checks for updates when new up
>
<div
class="leftSide"
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-downloading"
>
Downloading version some-version...
</div>
<div
class="Spinner singleColor"
/>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -266,9 +308,21 @@ exports[`installing update when started when user checks for updates when new up
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-download-failed"
>
Download of update failed
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -349,9 +403,21 @@ exports[`installing update when started when user checks for updates when new up
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-available"
>
some-version is available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -414,9 +480,21 @@ exports[`installing update when started when user checks for updates when no new
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`periodical checking of updates given updater is enabled and configurati
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`selection of update stability when started renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -15,7 +15,6 @@ import asyncFn from "@async-fn/jest";
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
describe("installing update", () => {
@ -24,19 +23,17 @@ describe("installing update", () => {
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
let setUpdateOnQuitMock: jest.Mock;
let showInfoNotificationMock: jest.Mock;
beforeEach(() => {
jest.useFakeTimers();
applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
quitAndInstallUpdateMock = jest.fn();
checkForPlatformUpdatesMock = asyncFn();
downloadPlatformUpdateMock = asyncFn();
setUpdateOnQuitMock = jest.fn();
showInfoNotificationMock = jest.fn(() => () => {});
rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
@ -89,7 +86,7 @@ describe("installing update", () => {
});
it("notifies the user that checking for updates is happening", () => {
expect(showInfoNotificationMock).toHaveBeenCalledWith("Checking for updates...");
expect(rendered.getByTestId("app-update-checking")).toBeInTheDocument();
});
it("renders", () => {
@ -98,8 +95,6 @@ describe("installing update", () => {
describe("when no new update is discovered", () => {
beforeEach(async () => {
showInfoNotificationMock.mockClear();
await checkForPlatformUpdatesMock.resolve({
updateWasDiscovered: false,
});
@ -108,7 +103,7 @@ describe("installing update", () => {
});
it("notifies the user", () => {
expect(showInfoNotificationMock).toHaveBeenCalledWith("No new updates available");
expect(rendered.getByTestId("app-update-not-available")).toBeInTheDocument();
});
it("does not start downloading update", () => {
@ -118,6 +113,12 @@ describe("installing update", () => {
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it.skip("when 5 seconds elapses, clears the notification to the user", () => {
jest.advanceTimersByTime(6000);
expect(rendered.getByTestId("app-update-idle")).toBeInTheDocument();
});
});
describe("when new update is discovered", () => {
@ -135,7 +136,7 @@ describe("installing update", () => {
});
it("notifies the user that download is happening", () => {
expect(showInfoNotificationMock).toHaveBeenCalledWith("Download for version some-version started...");
expect(rendered.getByTestId("app-update-downloading")).toBeInTheDocument();
});
it("renders", () => {
@ -152,7 +153,7 @@ describe("installing update", () => {
});
it("notifies the user about failed download", () => {
expect(showInfoNotificationMock).toHaveBeenCalledWith("Download of update failed");
expect(rendered.getByTestId("app-update-download-failed")).toBeInTheDocument();
});
it("renders", () => {
@ -169,6 +170,10 @@ describe("installing update", () => {
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
});
it("notifies the user about successful download", () => {
expect(rendered.getByTestId("app-update-available")).toBeInTheDocument();
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});

View File

@ -52,9 +52,21 @@ exports[`extensions - navigation using application menu renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`extensions - navigation using application menu when navigating to exten
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -577,9 +589,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1108,9 +1132,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1748,9 +1784,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2287,9 +2335,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2927,9 +2987,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -3743,9 +3815,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -4383,9 +4467,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -5199,9 +5295,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -5839,9 +5947,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -6378,9 +6498,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -6910,9 +7042,21 @@ exports[`add custom helm repository in preferences when navigating to preference
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -577,9 +589,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1108,9 +1132,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1692,9 +1728,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2223,9 +2271,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2754,9 +2814,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -3278,9 +3350,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -3839,9 +3923,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -4463,9 +4559,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -5024,9 +5132,21 @@ exports[`add helm repository from list in preferences when navigating to prefere
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -577,9 +589,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1101,9 +1125,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1517,9 +1553,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2041,9 +2089,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2457,9 +2517,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2981,9 +3053,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -3542,9 +3626,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -3958,9 +4054,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -4374,9 +4482,21 @@ exports[`listing active helm repositories in preferences when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`remove helm repository from list of active repositories in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -577,9 +589,21 @@ exports[`remove helm repository from list of active repositories in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1108,9 +1132,21 @@ exports[`remove helm repository from list of active repositories in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1639,9 +1675,21 @@ exports[`remove helm repository from list of active repositories in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -648,9 +660,21 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -848,9 +872,21 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
@ -914,9 +950,21 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
@ -980,9 +1028,21 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1576,9 +1636,21 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1776,9 +1848,21 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1976,9 +2060,21 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to application preferences given in some child
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -312,9 +324,21 @@ exports[`preferences - navigation to application preferences given in some child
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -636,9 +648,21 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -67,9 +67,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -301,9 +313,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -547,9 +571,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -793,9 +829,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1062,9 +1110,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1646,9 +1706,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2265,9 +2337,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2523,9 +2607,21 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2726,9 +2822,21 @@ exports[`preferences - navigation to extension specific preferences when navigat
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -2960,9 +3068,21 @@ exports[`preferences - navigation to extension specific preferences when navigat
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -636,9 +648,21 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -636,9 +648,21 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to telemetry preferences given URL for Sentry
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -298,9 +310,21 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -882,9 +906,21 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1478,9 +1514,21 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -1712,9 +1760,21 @@ exports[`preferences - navigation to telemetry preferences given no URL for Sent
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -636,9 +648,21 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -52,9 +52,21 @@ exports[`preferences - navigation using application menu renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`preferences - navigation using application menu when navigating to pref
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -53,9 +53,21 @@ exports[`show-about-using-tray renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -118,9 +130,21 @@ exports[`show-about-using-tray when navigating using tray renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -0,0 +1,124 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`status-bar-items-originating-from-extensions when application starts when extension with status bar items is loaded renders 1`] = `
<body>
<div>
<div
class="topBar"
>
<div
class="items"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
<div
class="item"
>
<div
data-testid="some-testId"
>
left1
</div>
</div>
<div
class="item"
>
<div
data-testid="some-testId"
>
left2
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
>
<div
class="item"
>
<div
data-testid="some-testId"
>
right3
</div>
</div>
<div
class="item"
>
<span
data-testid="some-testId"
>
right2
</span>
</div>
<div
class="item"
>
<span
data-testid="some-testId"
>
right1
</span>
</div>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
</body>
`;

View File

@ -0,0 +1,150 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { RenderResult } from "@testing-library/react";
import React from "react";
import type { GetRendererExtensionFake, TestExtension } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import getRandomIdInjectable from "../../common/utils/get-random-id.injectable";
describe("status-bar-items-originating-from-extensions", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.unoverride(getRandomIdInjectable);
rendererDi.permitSideEffects(getRandomIdInjectable);
});
});
describe("when application starts", () => {
let rendered: RenderResult;
let getRendererExtensionFake: GetRendererExtensionFake;
beforeEach(async () => {
rendered = await applicationBuilder.render();
getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
});
it("when multiple extensions with status bar items are loaded, shows items in correct order", () => {
const testExtension1 = getRendererExtensionFake({
id: "some-id",
name: "some-name",
statusBarItems: [
{
components: {
Item: () => <div data-testid="some-testId">extension1</div>,
position: "right",
},
},
],
});
const testExtension2 = getRendererExtensionFake({
id: "some-other-id",
name: "some-other-name",
statusBarItems: [
{
components: {
Item: () => <div data-testid="some-testId">extension2</div>,
position: "right",
},
},
],
});
applicationBuilder.extensions.renderer.enable(testExtension1, testExtension2);
const rightSide = rendered.getByTestId("status-bar-right");
const actual = getTestStatusBarTexts(rightSide, [
"extension1",
"extension2",
]);
expect(actual).toEqual(["extension2", "extension1"]);
});
describe("when extension with status bar items is loaded", () => {
let testExtension: TestExtension;
beforeEach(() => {
testExtension = getRendererExtensionFake({
id: "some-id",
name: "some-name",
statusBarItems: [
{
item: () => <span data-testid="some-testId">right1</span>,
},
{
item: () => <span data-testid="some-testId">right2</span>,
},
{
components: {
Item: () => <div data-testid="some-testId">right3</div>,
position: "right",
},
},
{
components: {
Item: () => <div data-testid="some-testId">left1</div>,
position: "left",
},
},
{
components: {
Item: () => <div data-testid="some-testId">left2</div>,
position: "left",
},
},
],
});
applicationBuilder.extensions.renderer.enable(testExtension);
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows right side status bar items in the correct order", () => {
const rightSide = rendered.getByTestId("status-bar-right");
const actual = getTestStatusBarTexts(rightSide, [
"right1",
"right2",
"right3",
]);
expect(actual).toEqual(["right3", "right2", "right1"]);
});
it("shows left side status bar items in the correct order", () => {
const leftSide = rendered.getByTestId("status-bar-left");
const actual = getTestStatusBarTexts(leftSide, ["left2", "left1"]);
expect(actual).toEqual(["left1", "left2"]);
});
it("when the extension is removed, shows there are no extension status bar items", () => {
applicationBuilder.extensions.renderer.disable(testExtension);
const actual = rendered.queryAllByTestId("some-testId");
expect(actual).toHaveLength(0);
});
});
});
});
const getTestStatusBarTexts = (actual: HTMLElement, expectedTexts: string[]) =>
Array.from(actual.children)
.map((elem) => elem.textContent)
.filter((elem) => elem && expectedTexts.includes(elem));

View File

@ -52,9 +52,21 @@ exports[`welcome - navigation using application menu renders 1`] = `
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
@ -115,9 +127,21 @@ exports[`welcome - navigation using application menu when navigating to welcome
>
<div
class="leftSide"
/>
data-testid="status-bar-left"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div

View File

@ -1,29 +0,0 @@
/**
* 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 { MessageChannel } from "../utils/channel/message-channel-injection-token";
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
export type ApplicationUpdateStatusEventId =
| "checking-for-updates"
| "no-updates-available"
| "download-for-update-started"
| "download-for-update-failed";
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type ApplicationUpdateStatusChannelMessage = { eventId: ApplicationUpdateStatusEventId; version?: string };
export type ApplicationUpdateStatusChannel = MessageChannel<ApplicationUpdateStatusChannelMessage>;
const applicationUpdateStatusChannelInjectable = getInjectable({
id: "application-update-status-channel",
instantiate: (): ApplicationUpdateStatusChannel => ({
id: "application-update-status-channel",
}),
injectionToken: messageChannelInjectionToken,
});
export default applicationUpdateStatusChannelInjectable;

View File

@ -5,21 +5,21 @@
import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { UpdateChannel } from "../update-channels";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type DiscoveredUpdateVersion = SyncBox<{ version: string; updateChannel: UpdateChannel } | null>;
const discoveredUpdateVersionInjectable = getInjectable({
id: "discovered-update-version",
instantiate: (di) => {
const createSyncBox = di.inject(createSyncBoxInjectable);
return createSyncBox<
| { version: string; updateChannel: UpdateChannel }
| null
>(
return createSyncBox(
"discovered-update-version",
null,
);
) as DiscoveredUpdateVersion;
},
injectionToken: syncBoxInjectionToken,

View File

@ -4,12 +4,16 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export interface ProgressOfDownload {
percentage: number;
failed?: string;
}
export type ProgressOfUpdateDownload = SyncBox<ProgressOfDownload>;
const progressOfUpdateDownloadInjectable = getInjectable({
id: "progress-of-update-download-state",

View File

@ -4,8 +4,11 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type UpdateIsBeingDownloaded = SyncBox<boolean>;
const updateIsBeingDownloadedInjectable = getInjectable({
id: "update-is-being-downloaded",

View File

@ -4,8 +4,11 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type UpdatesAreBeingDiscovered = SyncBox<boolean>;
const updatesAreBeingDiscoveredInjectable = getInjectable({
id: "updates-are-being-discovered",

View File

@ -1,23 +0,0 @@
/**
* 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 { ApplicationUpdateStatusChannelMessage } from "../../../common/application-update/application-update-status-channel.injectable";
import { messageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
import applicationUpdateStatusChannelInjectable from "../../../common/application-update/application-update-status-channel.injectable";
const broadcastChangeInUpdatingStatusInjectable = getInjectable({
id: "broadcast-change-in-updating-status",
instantiate: (di) => {
const messageToChannel = di.inject(messageToChannelInjectionToken);
const applicationUpdateStatusChannel = di.inject(applicationUpdateStatusChannelInjectable);
return (data: ApplicationUpdateStatusChannelMessage) => {
messageToChannel(applicationUpdateStatusChannel, data);
};
},
});
export default broadcastChangeInUpdatingStatusInjectable;

View File

@ -8,7 +8,6 @@ import updatesAreBeingDiscoveredInjectable from "../../../common/application-upd
import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import { runInAction } from "mobx";
import downloadUpdateInjectable from "../download-update/download-update.injectable";
import broadcastChangeInUpdatingStatusInjectable from "./broadcast-change-in-updating-status.injectable";
import checkForUpdatesStartingFromChannelInjectable from "./check-for-updates-starting-from-channel.injectable";
import withOrphanPromiseInjectable from "../../../common/utils/with-orphan-promise/with-orphan-promise.injectable";
import emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
@ -20,7 +19,6 @@ const processCheckingForUpdatesInjectable = getInjectable({
instantiate: (di) => {
const downloadUpdate = di.inject(downloadUpdateInjectable);
const selectedUpdateChannel = di.inject(selectedUpdateChannelInjectable);
const broadcastChangeInUpdatingStatus = di.inject(broadcastChangeInUpdatingStatusInjectable);
const checkingForUpdatesState = di.inject(updatesAreBeingDiscoveredInjectable);
const discoveredVersionState = di.inject(discoveredUpdateVersionInjectable);
const checkForUpdatesStartingFromChannel = di.inject(checkForUpdatesStartingFromChannelInjectable);
@ -34,8 +32,6 @@ const processCheckingForUpdatesInjectable = getInjectable({
params: { currentDateTime: getCurrentDateTime(), source },
});
broadcastChangeInUpdatingStatus({ eventId: "checking-for-updates" });
runInAction(() => {
checkingForUpdatesState.set(true);
});
@ -43,8 +39,6 @@ const processCheckingForUpdatesInjectable = getInjectable({
const result = await checkForUpdatesStartingFromChannel(selectedUpdateChannel.value.get());
if (!result.updateWasDiscovered) {
broadcastChangeInUpdatingStatus({ eventId: "no-updates-available" });
runInAction(() => {
discoveredVersionState.set(null);
checkingForUpdatesState.set(false);
@ -61,11 +55,6 @@ const processCheckingForUpdatesInjectable = getInjectable({
params: { version, currentDateTime: getCurrentDateTime() },
});
broadcastChangeInUpdatingStatus({
eventId: "download-for-update-started",
version,
});
runInAction(() => {
discoveredVersionState.set({
version,
@ -75,15 +64,7 @@ const processCheckingForUpdatesInjectable = getInjectable({
checkingForUpdatesState.set(false);
});
withOrphanPromise(async () => {
const { downloadWasSuccessful } = await downloadUpdate();
if (!downloadWasSuccessful) {
broadcastChangeInUpdatingStatus({
eventId: "download-for-update-failed",
});
}
})();
withOrphanPromise(async () => await downloadUpdate())();
};
},
});

View File

@ -38,6 +38,7 @@ const downloadUpdateInjectable = getInjectable({
runInAction(() => {
if (!downloadWasSuccessful) {
progressOfUpdateDownload.set({ percentage: 0, failed: "Download of update failed" });
discoveredVersionState.set(null);
}

View File

@ -1,57 +0,0 @@
/**
* 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 { ApplicationUpdateStatusChannel, ApplicationUpdateStatusEventId } from "../../common/application-update/application-update-status-channel.injectable";
import applicationUpdateStatusChannelInjectable from "../../common/application-update/application-update-status-channel.injectable";
import showInfoNotificationInjectable from "../components/notifications/show-info-notification.injectable";
import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token";
import { messageChannelListenerInjectionToken } from "../../common/utils/channel/message-channel-listener-injection-token";
const applicationUpdateStatusListenerInjectable = getInjectable({
id: "application-update-status-listener",
instantiate: (di): MessageChannelListener<ApplicationUpdateStatusChannel> => {
const channel = di.inject(applicationUpdateStatusChannelInjectable);
const showInfoNotification = di.inject(showInfoNotificationInjectable);
const eventHandlers: Record<ApplicationUpdateStatusEventId, { handle: (version?: string) => void }> = {
"checking-for-updates": {
handle: () => {
showInfoNotification("Checking for updates...");
},
},
"no-updates-available": {
handle: () => {
showInfoNotification("No new updates available");
},
},
"download-for-update-started": {
handle: (version) => {
showInfoNotification(`Download for version ${version} started...`);
},
},
"download-for-update-failed": {
handle: () => {
showInfoNotification("Download of update failed");
},
},
};
return {
channel,
handler: ({ eventId, version }) => {
eventHandlers[eventId].handle(version);
},
};
},
injectionToken: messageChannelListenerInjectionToken,
});
export default applicationUpdateStatusListenerInjectable;

View File

@ -0,0 +1,107 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { withInjectables } from "@ogre-tools/injectable-react";
import { observer } from "mobx-react";
import assert from "assert";
import React, { useState } from "react";
import { Spinner } from "../spinner";
import type { ProgressOfUpdateDownload } from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
import progressOfUpdateDownloadInjectable from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
import type { DiscoveredUpdateVersion } from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import type { UpdateIsBeingDownloaded } from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
import updateIsBeingDownloadedInjectable from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
import type { UpdatesAreBeingDiscovered } from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable";
import updatesAreBeingDiscoveredInjectable from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable";
import { now as reactiveDateNow } from "mobx-utils";
interface Dependencies {
progressOfUpdateDownload: ProgressOfUpdateDownload;
discoveredVersionState: DiscoveredUpdateVersion;
downloadingUpdateState: UpdateIsBeingDownloaded;
checkingForUpdatesState: UpdatesAreBeingDiscovered;
}
interface EndNoteProps {
version?: string;
note: (version: string) => JSX.Element;
}
const EndNote = observer(({ version, note }: EndNoteProps) => {
const [start] = useState(Date.now());
if (start + 5000 <= reactiveDateNow()) {
return idle();
}
return note(version ?? "");
});
const checking = () => (
<>
<Spinner/>
<div data-testid="app-update-checking">Checking for updates...</div>
</>
);
const available = (version: string) => <div data-testid="app-update-available">{`${version ?? "Update"} is available`}</div>;
const notAvailable = () => <div data-testid="app-update-not-available">No new updates available</div>;
const downloading = (version: string) => {
return (
<>
<div data-testid="app-update-downloading">{`Downloading version ${version}...`}</div>
<Spinner/>
</>
);
};
const downloadFailed = (errMsg: string) => <div data-testid="app-update-download-failed">{errMsg}</div>;
const idle = () => <div data-testid="app-update-idle"></div>;
export const NonInjectedAutoUpdateComponent = observer(({
progressOfUpdateDownload,
discoveredVersionState,
downloadingUpdateState,
checkingForUpdatesState,
}: Dependencies) => {
const discoveredVersion = discoveredVersionState.value.get();
const { failed } = progressOfUpdateDownload.value.get();
if (downloadingUpdateState.value.get()) {
assert(discoveredVersion);
return downloading(discoveredVersion.version);
}
if (checkingForUpdatesState.value.get()) {
return checking();
}
if ( discoveredVersion) {
return <EndNote note={available} version={discoveredVersion.version} />;
}
if ( failed ) {
return <EndNote note={downloadFailed} version={failed} />;
}
return <EndNote note={notAvailable} />;
});
export const AutoUpdateComponent = withInjectables<Dependencies>(NonInjectedAutoUpdateComponent, {
getProps: (di, props) => ({
progressOfUpdateDownload: di.inject(progressOfUpdateDownloadInjectable),
discoveredVersionState: di.inject(discoveredUpdateVersionInjectable),
downloadingUpdateState: di.inject(updateIsBeingDownloadedInjectable),
checkingForUpdatesState: di.inject(updatesAreBeingDiscoveredInjectable),
...props,
}),
});

View File

@ -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 { computed } from "mobx";
import { AutoUpdateComponent } from "./auto-update-component";
import { statusBarItemInjectionToken } from "./status-bar-item-injection-token";
const autoUpdateStatusBarItemInjectable = getInjectable({
id: "auto-update-status-bar-item",
instantiate: () => ({
component: AutoUpdateComponent,
position: "left" as const,
visible: computed(() => true),
}),
injectionToken: statusBarItemInjectionToken,
});
export default autoUpdateStatusBarItemInjectable;

View File

@ -1,78 +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 { getInjectable } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx";
import { computed } from "mobx";
import type {
StatusBarItemProps,
StatusBarRegistration,
} from "./status-bar-registration";
import statusBarItemsInjectable from "./status-bar-items.injectable";
export interface RegisteredStatusBarItems {
right: React.ComponentType<StatusBarItemProps>[];
left: React.ComponentType<StatusBarItemProps>[];
}
interface Dependencies {
registrations: IComputedValue<StatusBarRegistration[]>;
}
function getRegisteredStatusBarItems({ registrations }: Dependencies): IComputedValue<RegisteredStatusBarItems> {
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);
}
}
// This is done so that the first ones registered are closest to the corner
res.right.reverse();
return res;
});
}
const registeredStatusBarItemsInjectable = getInjectable({
id: "registered-status-bar-items",
instantiate: (di) => getRegisteredStatusBarItems({
registrations: di.inject(statusBarItemsInjectable),
}),
});
export default registeredStatusBarItemsInjectable;

View File

@ -0,0 +1,17 @@
/**
* 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 { IComputedValue } from "mobx";
import type React from "react";
export interface StatusBarItem {
component: React.ComponentType<any>;
position: "left" | "right";
visible: IComputedValue<boolean>;
}
export const statusBarItemInjectionToken = getInjectionToken<StatusBarItem>({
id: "status-bar-item",
});

View File

@ -0,0 +1,85 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Injectable } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import type { StatusBarItem } from "./status-bar-item-injection-token";
import { statusBarItemInjectionToken } from "./status-bar-item-injection-token";
import type { StatusBarRegistration } from "./status-bar-registration";
import React from "react";
import getRandomIdInjectable from "../../../common/utils/get-random-id.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import type { Logger } from "../../../common/logger";
const statusBarItemRegistratorInjectable = getInjectable({
id: "status-bar-item-registrator",
instantiate: (di) => (extension) => {
const rendererExtension = extension as LensRendererExtension;
const getRandomId = di.inject(getRandomIdInjectable);
const logger = di.inject(loggerInjectable);
return rendererExtension.statusBarItems.flatMap(
toItemInjectableFor(rendererExtension, getRandomId, logger),
);
},
injectionToken: extensionRegistratorInjectionToken,
});
export default statusBarItemRegistratorInjectable;
const toItemInjectableFor = (extension: LensRendererExtension, getRandomId: () => string, logger: Logger) => {
return (registration: StatusBarRegistration): Injectable<StatusBarItem, StatusBarItem, void>[] => {
const id = `${getRandomId()}-status-bar-item-for-extension-${extension.sanitizedExtensionId}`;
let component: React.ComponentType;
let position: "left" | "right";
if (registration?.item) {
const { item } = registration;
position = "right";
component =
() => (
<>
{
typeof item === "function"
? item()
: item
}
</>
);
} else if (registration?.components) {
const { position: pos = "right", Item } = registration.components;
if (pos !== "left" && pos !== "right") {
throw new TypeError("StatusBarRegistration.components.position must be either 'right' or 'left'");
}
position = pos;
component = Item;
} else {
logger.warn("StatusBarRegistration must have valid item or components field");
return [];
}
return [getInjectable({
id,
instantiate: () => ({
component,
position,
visible: computed(() => true),
}),
injectionToken: statusBarItemInjectionToken,
})];
};
};

View File

@ -1,21 +0,0 @@
/**
* 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 { computed } from "mobx";
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
const statusBarItemsInjectable = getInjectable({
id: "status-bar-items",
instantiate: (di) => {
const extensions = di.inject(rendererExtensionsInjectable);
return computed(() =>
extensions.get().flatMap((ext) => ext.statusBarItems),
);
},
});
export default statusBarItemsInjectable;

View File

@ -0,0 +1,61 @@
/**
* 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 { IComputedValue } from "mobx";
import { computed } from "mobx";
import type { StatusBarItemProps } from "./status-bar-registration";
import type { StatusBarItem } from "./status-bar-item-injection-token";
import { statusBarItemInjectionToken } from "./status-bar-item-injection-token";
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
export interface StatusBarItems {
right: React.ComponentType<StatusBarItemProps>[];
left: React.ComponentType<StatusBarItemProps>[];
}
interface Dependencies {
registrations: IComputedValue<StatusBarItem[]>;
}
function getStatusBarItems({ registrations }: Dependencies): IComputedValue<StatusBarItems> {
return computed(() => {
const res: StatusBarItems = {
left: [],
right: [],
};
for (const registration of registrations.get()) {
const { position = "right", component, visible } = registration;
if (!visible.get()) {
continue;
}
res[position].push(component);
}
// This is done so that the first ones registered are closest to the corner
res.right.reverse();
return res;
});
}
const statusBarItemsInjectable = getInjectable({
id: "status-bar-items",
instantiate: (di) => {
const computedInjectMany = di.inject(
computedInjectManyInjectable,
);
return getStatusBarItems({
registrations: computedInjectMany(statusBarItemInjectionToken),
});
},
});
export default statusBarItemsInjectable;

View File

@ -5,18 +5,16 @@
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 type { IObservableArray } from "mobx";
import { computed, observable } from "mobx";
import type { DiContainer } from "@ogre-tools/injectable";
import type { StatusBarItems } from "./status-bar-items.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";
import type { ApplicationBuilder } from "../test-utils/get-application-builder";
import { getApplicationBuilder } from "../test-utils/get-application-builder";
import getRandomIdInjectable from "../../../common/utils/get-random-id.injectable";
class SomeTestExtension extends LensRendererExtension {
constructor(statusBarItems: IObservableArray<any>) {
@ -35,21 +33,29 @@ class SomeTestExtension extends LensRendererExtension {
}
describe("<StatusBar />", () => {
let render: DiRender;
let di: DiContainer;
let statusBarItems: IObservableArray<any>;
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
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)]));
applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.unoverride(getRandomIdInjectable);
rendererDi.permitSideEffects(getRandomIdInjectable);
});
it("renders w/o errors", () => {
const { container } = render(<StatusBar />);
applicationBuilder.extensions.renderer.enable(new SomeTestExtension(statusBarItems));
di = applicationBuilder.dis.rendererDi;
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
});
it("renders w/o errors", async () => {
const { container } = await applicationBuilder.render();
expect(container).toBeInstanceOf(HTMLElement);
});
@ -62,26 +68,27 @@ describe("<StatusBar />", () => {
[],
[{}],
{},
])("renders w/o errors when registrations are not type compliant (%p)", val => {
])("renders w/o errors when registrations are not type compliant (%p)", async val => {
statusBarItems.replace([val]);
expect(() => render(<StatusBar />)).not.toThrow();
await expect(applicationBuilder.render()).resolves.toBeTruthy();
});
it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", () => {
it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", async () => {
const testId = "testId";
const text = "heee";
di.override(statusBarItemsInjectable, () => computed(() => [
{ item: <span data-testid={testId} >{text}</span> },
] as StatusBarRegistration[]));
di.override(statusBarItemsInjectable, () => computed(() => ({
right: [ () => <span data-testid={testId} >{text}</span> ],
left: [],
}) as StatusBarItems));
const { getByTestId } = render(<StatusBar />);
const { getByTestId } = await applicationBuilder.render();
expect(getByTestId(testId)).toHaveTextContent(text);
});
it("renders items [{item: () => React.ReactNode}] (4.0.0-rc.1+)", () => {
it("renders items [{item: () => React.ReactNode}] (4.0.0-rc.1+)", async () => {
const testId = "testId";
const text = "heee";
@ -89,13 +96,13 @@ describe("<StatusBar />", () => {
item: () => <span data-testid={testId} >{text}</span>,
}]);
const { getByTestId } = render(<StatusBar />);
const { getByTestId } = await applicationBuilder.render();
expect(getByTestId(testId)).toHaveTextContent(text);
});
it("sort positioned items properly", () => {
it("sort positioned items properly", async () => {
statusBarItems.replace([
{
components: {
@ -122,7 +129,7 @@ describe("<StatusBar />", () => {
},
]);
const { getAllByTestId } = render(<StatusBar />);
const { getAllByTestId } = await applicationBuilder.render();
const elems = getAllByTestId("sortedElem");
const positions = elems.map(elem => elem.textContent);

View File

@ -8,14 +8,14 @@ import styles from "./status-bar.module.scss";
import React from "react";
import { observer } from "mobx-react";
import { withInjectables } from "@ogre-tools/injectable-react";
import type { RegisteredStatusBarItems } from "./registered-status-bar-items.injectable";
import registeredStatusBarItemsInjectable from "./registered-status-bar-items.injectable";
import type { StatusBarItems } from "./status-bar-items.injectable";
import statusBarItemsInjectable from "./status-bar-items.injectable";
import type { IComputedValue } from "mobx";
export interface StatusBarProps {}
interface Dependencies {
items: IComputedValue<RegisteredStatusBarItems>;
items: IComputedValue<StatusBarItems>;
}
const NonInjectedStatusBar = observer(({ items }: Dependencies & StatusBarProps) => {
@ -23,14 +23,14 @@ const NonInjectedStatusBar = observer(({ items }: Dependencies & StatusBarProps)
return (
<div className={styles.StatusBar}>
<div className={styles.leftSide}>
<div className={styles.leftSide} data-testid="status-bar-left">
{left.map((Item, index) => (
<div className={styles.item} key={index}>
<Item />
</div>
))}
</div>
<div className={styles.rightSide}>
<div className={styles.rightSide} data-testid="status-bar-right">
{right.map((Item, index) => (
<div className={styles.item} key={index}>
<Item />
@ -44,7 +44,7 @@ const NonInjectedStatusBar = observer(({ items }: Dependencies & StatusBarProps)
export const StatusBar = withInjectables<Dependencies, StatusBarProps>(NonInjectedStatusBar, {
getProps: (di, props) => ({
items: di.inject(registeredStatusBarItemsInjectable),
items: di.inject(statusBarItemsInjectable),
...props,
}),
});

View File

@ -17,8 +17,10 @@ export class TestExtension extends LensRendererExtension {}
export type FakeExtensionData = SetRequired<Partial<LensRendererExtension>, "id" | "name">;
export const getRendererExtensionFakeFor = (builder: ApplicationBuilder) => (
function getRendererExtensionFake({ id, name, ...rest }: FakeExtensionData) {
export type GetRendererExtensionFake = (fakeExtensionData: FakeExtensionData) => TestExtension;
export const getRendererExtensionFakeFor = (builder: ApplicationBuilder): GetRendererExtensionFake => (
function getRendererExtensionFake({ id, name, ...rest }) {
const instance = new TestExtension({
id,
absolutePath: "irrelevant",